Question about contract/token upgrades


#1

Hi everyone,

I am pursuing a contract that has multiple potential phases. At first its calling for what is essentially a typical token, then down the road it could lead to integrations with a NFT (ERC1155-style would be ideal). Is it possible for me to update a published contract with a new version that adds to the functionality of the original tokens or would the entire token protocol akin to ERC1155 need to be implemented at the gate?


#2

Hey,

I think you should adopt a modular approach to creating contracts if you wish to add certain functions in future. This means replacing the contract call _tag in the msg field of certain master contract to a new child contract address with the new functions.

Smart contracts source code in general should not be modified as it is immutable.


#3

Certainly. What you are describing here is a need for an “upgrading contract”.

Once a contract is deployed to the blockchain, it is final and cannot be changed. To update your contract, you will need a versioning system. Versioning system concept in Scilla is similar to how you would do it in Ethereum (as described here: https://ethereum.stackexchange.com/questions/2404/upgradeable-smart-contracts).

Since this is a common question, here’s an illustration to clarify things for everyone.

In this illustration, I started with a contract (i.e. Contract V1). I want to patch some implementation issues to contract V2.

The idea is to use a RelayContract to do it. Instead of sending transactions to the Contract V1 directly. I would send it to a RelayContract. The RelayContract would store the contract address of the most updated contract. You will want to enforce some access control mechanism to ensure that only the right people (e.g. only you) can update the new contract address.

Since the user only interacts with the RelayContract, you can redirect his messages to the most updated contract address. In this illustration, the InvokeFoo transition will redirect the caller’s message to the Foo transition in the actual contract. You can specify which transition you want to invoke via _tag.

This approach has a few drawbacks though:

  • You will require the same transition interface. For example, if you only have a transition called foo ( val: String), you cannot update to a new contract address with a new transition bar (val: Uint128, msg: String). Once you deploy the RelayContract, you cannot change it!
  • From an engineering perspective, it is harder to test your contracts as the presence of a RelayContract.
  • The cost will be higher as every transaction has to pass through one extra contract (RelayContract).

Hope that helps.