Once deployed to the blockchain, a contract stays there forever
Everyone has heard about dozens of companies over the years that endured helplessness and lost fortunes because of the immutability factor of blockchain, that supposedly is its strength. We want to help in securing users against such hacks and vulnerabilities. So we have crafted a complete series (this blog just being part 1) on writing upgradeable smart contracts so that you can atleast make sure you are covered.
Scope of this series
We would cover 4 Upgradeability Improvement Protocols in this series or UIPs, as they will be referred to from hereon. Each one will be covered in individual parts.
We would cover the following-
- A brief summary of each upgradeability protocol
- Sample code for each of the examples
- Reproduction of working on remix
- Advantages and limitations to each approach
Note- If you dont understand the approach during the summary, give it time to sink in till the implementation during step 3.
Remix would be the tool used by us to run and test the code.
What you are expected to know
- Basic understanding on how to write solidity smart contracts and know how to run remix. If you want to get a head start on that, check out this post ( https://www.techracers.com/smart-contract-solidity )
- Have read about the modular helper contracts (Ownable, SafeMath etc). It will be taken for granted you know about the functions and modifiers that they implement. You can take a look at them with inline comments, here ( https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol ) ( https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/ownership/Ownable.sol )
Note- I will be skipping out the above mentioned modular imports so that code remains concise.
Bringing about upgradeability
So to track back our introduction, what you heard about smart contracts is not completely true. Yes, once deployed to the mainnet, there is nothing you can do to change the existing logic. Nevertheless, smart contracts can be built with certain upgradeability protocols. Let’s walk through UIP 1. We would be using token contracts for simplicity, but each can be extended to ANY type of a smart contract.
UIP1. The Upgrade Agent
In basic language, this is fair and simple. Let’s assume there are 100 token holders having some balance. We get them to transfer their balances from the old to the new contract with separate transactions for each token holder. Every holder will have to upgrade themselves. Now for the advanced readers, the old token contract will have an upgrade function, that each holder can call. It simply calls the new token contract and transfers the balance to it. This is mostly done if the old token contract is found with a bug or if they want to change their ERC standard from the old 20 to some of the new ones. An example snippet of the code can be found below.
The old token contract will look like this(highly simplified).
And the new token contract must be able to catch these tokens using the
upgradeFrom function and should be something along these lines
Steps to reproduce working on remix
You can find a link to the entire code with the imports here. Paste the entire code into the remix editor and compile it. You should get the contracts, OldToken and NewToken in the ‘run’ tab. Lets go through the steps-
- Create the OldToken contract. You should get 10000 tokens as initialized in the constructor. Call the constant balances function to make sure.
- Create the NewToken contract. The constructor takes address of the old token contract for parameters.
- Now go back to the OldToken contract and call the
setUpgradeAgentfunction and input the address of the new token contract as params.
- Now that the setup is all done, we are ready to upgrade. Just call the
upgradefunction and input the number of tokens you want to upgrade(you obviously cannot upgrade more than you have :P). Upgrade event emitted makes sure that the upgrades can be tracked. Look for it in the logs part of details in the console.
- Go and witness it by checking your balance in the NewToken contract.
Advantages to the UpradeAgent-
- It is simple. Usually said that the simplest solutions are the best ones.
- Transparent process. Everyone can look into the verified contract on etherscan and look for themselves what goes on.
- Users have a say in the upgrade which is the heart of the blockchain fundamental.
All of the approaches that we discuss have some or the other limitations associated with them. It is always a trade-off between a few dozen factors when it comes to upgradeability in blockchain.
- Each user has to upgrade on their own. This calls for thousands of separate transactions that the users will have to make.
- Too slow. Upgrade process can last for days, weeks, even years.
- If there is an inactive token holder or if someone has lost his private keys, the upgrade process might never reach completion.
- Some users might be holding the tokens in cold storage wallets, which might make this process a bit too lengthy for them.
- Not every token holder is well equipped to be calling a smart contract function. Instructions can be given to them, but it almost causes panic to someone who doesn’t understand the workings of ethereum.
- The new token contract will have a new address(obviously). This means that the contract creator has to go through all the trouble of listing the contract on etherscan, exchanges, etc. again.
And that’s it for the first tutorial. You just learnt to write a simple upgradeability enabled smart contract that allows you to transfer data to another improved version. Make sure you check the complete codebase here.
But this is not what we were looking for! Read on to the next part of the series to explore the better contract architecture of UIP2.