Updateable Contracts

Published by Mario Oettler on

Updateable contracts allow for updating the functionality of a contract. In some cases, like bugs and improvements, it is desirable, but it also renders the whole idea of an immutable code on the blockchain useless.

Here, we want to consider a few ways how to update a smart contract.

Deploy a New Contract

The easiest way to update a smart contract is to deploy a new contract and transfer all state manually from the old one to the new one.

The benefit is that users can still rely on the old contract if it wasn’t shut down. They are free to choose whether to use the old version or the new.

The problem is that transferring the state is time-consuming, expensive, and error-prone. At the same time, you might double the assets a user owns since they exist in the old contract and in the new one too.

Besides that, users need to know the new address of the new contract.

Use a Proxy with an Interface

In this approach, you have two contracts. The first one is the proxy contract that implements an interface, and the second one is a logic contract that does all the actual work. The user interacts with the proxy contract which in turn forwards the function calls to the logic contract.

The forwarding is done with call() or delegatecall().

Since those sub contracts are referred by their address, it is possible to change the contract by changing its address during runtime. Delegatecall has the advantage that the storage and balance belong to the proxy. This makes it easier to replace the logic contract because it didn’t store any user variables and balances.

The problem with this approach is that if the new logic contract has different functions than the old logic contract, with its interface breaks.

Use a Proxy with Fallback

Instead of using an interface with each function of the logic contract defined, a proxy can use a fallback function. The user always calls the fallback function and passes the function name of the logic contract. The fallback function then forwards this call to the respective function in the logic contract. This has the advantage that the logic contract doesn’t need to change even if the logic contract features new functions. The user, however, has to update its ABI and change its function calls respectively.