# "Advanced" Smart Contracting I

By [omnifient](https://paragraph.com/@omnifient) · 2023-07-21

---

(Note: this article is intended to give readers a superficial understanding of things, with pointers to references that let you go deep into the sub-topics.)

So you’ve been writing smart contracts for a while now, and you’ve gone beyond the basic counter and PFP NFT stuff, venturing into DeFi or GameFi or MusicFi or WhateverFi with contracts spanning over the 24KB, and you’ve deployed things going beyond the first iteration, and you’re now building new features on top and suddenly you realize you wanna keep the same addresses and gotta break down the code cause it’s too big to fit into a single file and you’re wondering how did you get into this mess.

Welcome to Advanced Smart Contracting I. There will be a II, eventually. Maybe a III, possibly. More than that, idk.

### Smart contracts are immutable

right? Right? RIGHT? Welcome to the “it depends” world, AKA The Real World, where things are never quite black and white.

When a contract is deployed, it goes and lives forever in some address in the blockchain, e.g. 0x…123, with some code and storage.Yes, that address is now forever associated with a piece of code that is immutable. But the data will most certainly change, unless you’re programming a no-so-smart brick contract.

Ok, but what am I trying to say? Well, the data storage of a smart contract can change. And there’s this thing called a fallback function, and this thing called delegatecall, and you mix these things you end up with something called the Proxy Pattern.

And what can you do with this Proxy Pattern? How about telling your function to point to a different smart contract to execute?

Yes, we now have a way for a smart contract to change the code that runs. Bye bye immutability, so long suckers!

### Upgrades

What about this upgradeability thing? Our PFP NFT v1 has the images hosted on some Photobucket, and our users have complained about it because they don’t like it, so now we wanna put the images on-chain. But `setImageURI` isn’t enough, we gotta change the implementation - we gotta upgrade the contract.

Of course, there are different ways of doing this. The basic approach is to deploy the new version, migrate the data over to the new contract with the images on-chain - but we won’t be able to keep the same address (and that’s acceptable in most cases).

What if we want to keep the original contract address? Then we need to be a bit more sophisticated, and that’s where the Proxy Pattern can help us - the proxy (which is the original address) can point to a new implementation. But understand that depending on the complexity of the changes, you might be able to upgrade without a proxy.

But of course, we gotta be aware that these techniques exist before we deploy things (plus there are a few different ways to build proxies).

Here’s a good article about the specific topic of Upgrades.

[https://ethereum.org/en/developers/docs/smart-contracts/upgrading/](https://ethereum.org/en/developers/docs/smart-contracts/upgrading/)

### Proxies

A proxy contract is simply a smart contract that sits in front of other smart contracts, and routes the call to an implementation contract.

Here’s a very basic but concrete example - it shows how we can “change” the implementation of the contract. In reality, the code of the smart contract isn’t changing, it’s the data that changes, but in practice this causes different code to execute!

![Example of a Basic Proxy](https://storage.googleapis.com/papyrus_images/40aa35362f268d09587b18573ae3e05c032fff23013e6b91fc29b3689e815251.png)

Example of a Basic Proxy

The above example is exposing an interface (the `sayGM` function) in the `ProxyContract` , which itself keeps track of an interface (`IGMImpl`) to call.

But the EVM makes it possible to bypass that, and have an ultra-generic proxy that can hold any function!!!

### fallback + delegatecall

The `fallback` function is a special function in a smart contract, and

> the [fallback function](https://docs.soliditylang.org/en/latest/contracts.html#fallback-function) is executed when a function call does not match functions specified in a contract.

i.e. if someone calls your contract with a function that’s not explicitly defined in the contract, then `fallback()` is executed.

The `delegatecall` is

> an opcode that allows a contract to call another contract, while the actual code execution happens in the context of the calling contract

The previous example actually shows a `delegatecall`, but it’s not explicitly mentioned; When the `ProxyContract` executes `impl.x()`, it’s actually doing a `delegatecall` to the implementation contract (`GM1Contract` or `BDContract` or `GM2Contract`).

So by joining these two things, you can write a Proxy Contract that is ultra-generic, because it does not need to know what interface to expose!

> Making the proxy pattern work requires writing a custom fallback function that specifies how the proxy contract should handle function calls it does not support. In this case the proxy's fallback function is programmed to initiate a delegatecall and reroute the user's request to the current logic contract implementation.

Ok, I’ve told you about smart contract immutability, upgrades, proxies, fallback and delegatecall. Now what?

(PS: what I didn’t talk about is how the `ProxyContract` is the one to hold the state AKA the data, which means changing implementations must be done carefully, because it can screw up the data because it’s based on the memory layout.)

(PSS: I also didn’t talk about this thing called selector clash that happens when the `ProxyContract` and the `ImplementationContract` have the same function and `delegatecall` now isn’t sure which function to execute and this can cause headaches.)

### The Many Roads to Rome

Or from Rome?

Ok, so everyone’s using pretty much the same [Proxy Contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Proxy.sol) (or something very similar), since it’s ultra-generic and actually solves all the requirements, which is kinda crazy cause this never happens.

So **_when do things start to differ_**?

Well, it’s when you start going into **_how to organize things_**.

**Kinda Transparent**  
Like, if you want things to be upgradeable, that means you want to be able to change e.g. the address of the implementation contract - in the previous example, that would be calling `setImpl(newImpl)`. So now your Proxy Contract isn’t just the `fallback` function, and starts to have other functions, and most likely these should be guarded by some control access like the `onlyOwner` [modifier](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) (or something more sophisticated), and you might even have to tweak your `fallback` to check for the admin because you want to avoid selector clashes, and now you end up implementing what’s called the _Transparent Proxy Pattern_.

With this pattern, the code to upgrade is inside the `ProxyContract` itself, like in the previous example.

**UUPS not UPS**  
What if you don’t want to keep the code to upgrade in the `ProxyContract`? Well, you can put it inside the `ImplementationContract`, and that’s what the [_Universal Upgradeable Proxy Standard_](https://eips.ethereum.org/EIPS/eip-1822) is all about.

Following the example, that means that `IGMImpl` should have a `setImpl` function declared, and `GM1Contract`, `BDContract`, `GM2Contract` would have to implement it.

**Lighthouse would be a better name**  
You heard that _All problems in computer science can be solved by another level of indirection_ (and that’s actually what a Proxy is!), so you became one of those modularity freaks who decides to factor out the address of the `ImplementationContract` and move it to its own smart contract called `ImplRetriever` with a `getImpl()`, and have the `ProxyContract` do `implRetriever.getImpl().x()` because that’s so much better.

Well done, you’re building a _Beacon Proxy_. This is a useful pattern when you have multiple proxies sharing the same implementation (why would you do that? well…), and it’ll make it easier for you to change the pointer to the implementation.

**Diamonds are Forever**  
Do you wanna get extra fancy? Just get a [Diamond](https://eips.ethereum.org/EIPS/eip-2535), and you’ll be able to split your implementation logic into multiple implementation contracts, and do things like partial upgrades, and have a “safe” buffer for large contracts.

It really works, but you should read the ERC to get a full grasp of things.

**Routers in Proxyland**  
This great talk about proxies goes in-depth into the technical issues with proxies, and how to solve them, and also comes up with a variation of the Diamond Standard, which they call _Router Proxies_.

[![]({{DOMAIN}}/editor/youtube/play.png)](https://www.youtube.com/watch?v=URxPvAaT7vE)

### Final Thoughts

There’s a strong current of thought that tells you to avoid proxies and upgrades at all costs, and that smart contracts should be purely immutable. And I don’t disagree with it, since it makes things so much easier to reason about, and it makes change explicit and directly visible, which is one of the pillars of blockchain.

But [YMMV](https://www.urbandictionary.com/define.php?term=ymmv).

---

*Originally published on [omnifient](https://paragraph.com/@omnifient/advanced-smart-contracting-i)*
