Smart contracts for Business

Smart contract upgradeability

Smart contracts for Business

Ask any seasoned software engineer, what was his biggest challenge ever.

Each one of them will tell you a tale, of course, narration would matter for anyone to grasp the context of the problem they were solving. Step back and take a bird's view of what they were grappling with and ask for confirmation on, if it was related to changes in software requirements, 90% will nod their head with confirmation.

Most will follow up with an affirmation and say,

"Business always changes, software engineering is mostly about designing, provisioning and developing for a change to support the very fluid business needs"

Like in our lives, software change is also inevitable.

Blockchain is Immutable

Blockchain technology brought a new foundation which is different from above, Immutability. The transition from Web2 to Web3 is so overwhelming that we forget to challenge this new foundation in the first instance. Experience taught us something opposite all along. At least, it is true for my context.

Once a smart contract is deployed on Blockchain, the code for that deployed instance cannot change. Yes, it makes total sense as we want this data to remain as a permanent record. Once the facts agree, a record is formed and it should not change is the key aspect of blockchain technology. We all agree to that.

We have very sharp minds around us and hence every problem has at least of pair of solutions.

Facts break down

Business logic changes, but records should hold. Historical records should not change as they were based on facts then.

So, the solution was to separate the business logic from the data and keep the facts immutable while provisioning for future business changes, leading to the development of upgradeable Smart contract patterns. If you think about it, it is similar to other software engineering too, except for data ownership and the ability to change anything due to the undeniable power in the hands of a few.

Upgradeable Smart Contract Patterns

As a general approach for upgradeability, the storage and business logic are separated using the concept of delegate call along with a fallback function. The combination of these two gives a very generic approach to separate logic from data and lets logic operate on the data. (This is a topic for another day)

a) Transparent proxy pattern

In a transparent proxy pattern, the proxy contract is what every consuming contract will hold a reference to. The proxy contract also has data, but the business functionality is separated into Logic/Implementation contracts that can be replaced with new logic contracts anytime in future.

Three key players in the code below:

  1. admin(ProxyAdmin)

A contract that holds entitlements to upgrade business logic for proxy

  1. proxy

A contract that holds storage and depends on implementation contracts for business functionality. Any consumer contract holds a reference to a proxy contract.

  1. Implementation contracts

Business functions working on top of data.

        admin = new ProxyAdmin();
        implementationV1 = new MyBusinessLogicV1();
        proxy = new TransparentUpgradeableProxy(address(implementationV1), address(admin), "");
        wrappedProxyV1 = MyBusinessLogicV1(address(proxy));

        // Business changes, needs new functionality
        implementationV2 = new MyBusinessLogicV2();
        admin.upgrade(proxy, address(implementationV2));
        // re-wrap the proxy
        wrappedProxyV2 = MyBusinessLogicV2(address(proxy));

b) Universal upgradeable proxy standard (UUPS)

UUPS is very similar to a transparent proxy contract except for how the upgrade is triggered. In the case of UUPS, the upgrade is triggered by the implementation contracts themselves rather than a proxy admin.

There is a unique storage slot in the proxy contract to store the address of the logic contract that it points to. Whenever the logic contract is upgraded, that storage slot is updated with the new logic contract address. The function to upgrade the contracts should be a protected function to avoid unauthorized access.

        implementationV1 = new MyBusinessLogicV1();
        proxy = new UUPSProxy(address(implementationV1), "");
        wrappedProxyV1 = MyBusinessLogicV1(address(proxy));

        // Business changes, needs new functionality
        implementationV2 = new MyBusinessLogicV2();
        wrappedProxyV1.upgradeTo(address(implementationV2));
        // re-wrap the proxy
        wrappedProxyV2 = MyBusinessLogicV2(address(proxy));

Now, that we have a grasp of how the upgradeable patterns work for smart contracts,

it is strongly advised to use the Openzepplien library to implement the upgradable smart contracts as there are certain challenges related to storage location clash and function name clash that is already addressed by Openzepplien library.

https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable

A wealth of information at AuditOne

AuditOne has a repository of information that helped me through the journey to grasp some of these key concepts.

Please refer to the below link.

auditone.notion.site/auditone/bb52d390910e4..

To learn more about AuditOne, visit their website.

auditone.io

They also conduct quizzes and CTF challenges which help in verifying the progress, and also a great place to meet like-minded people. Join their discord channel to explore more.