Hey there! After working on compiling the state of smart contract upgrades, I wanted to try out a variation on a pattern, to see if I could get a more gas-efficient proxy. Here I’m focusing on less gas overhead per call, but the end result seems also cheap in terms of deployment, since the proxy itself ended up being pretty thin.
The pattern I wanted to build on was the beacon proxy built by 0age, in which proxies don’t keep the implementation address, but an immutable reference to a beacon contract. The beacon, in turn, keeps track of the current implementation in storage. Whenever the proxy needs to delegate a call, it
CALLs the beacon to fetch the current implementation. Whenever the admin needs to upgrade, they just upgrade the beacon, effectively upgrading multiple proxies in a single tx.
Given that the goal was to reduce gas cost, I looked into removing the most expensive operation: loading the implementation address from storage with an
SLOAD. Now, the only alternative to storage for saving persistent data in an Ethereum contract is code - and it can actually be more gas efficient after the Istanbul gas repricing, as @Agusx1211 points out in this article.
The solution I ended up with is storing the implementation address in the beacon in code, and loading it from the proxy directly via
EXTCODECOPY, effectively requiring no
SLOADs during a
CALL. Beacons are deployed using
CREATE2 and dynamic runtime code, so to perform an upgrade they can be selfdestructed and recreated. To prevent the downtime associated with destroying and recreating the beacon, each proxy has two beacon: a main one, and a fallback that is used only when the first one is destroyed.
I ran this implementation versus other popular upgradeable proxy patterns, and it outperforms all of them in terms of gas overhead per call. It also has the nice property of beacons that multiple proxies can be upgraded with a single tx.
|Proxy||Gas cost||Gas overhead|
The code for the solution can be found in the repo below. Keep in mind that this is just a proof of concept, and should not be used in production. I’d love to hear your thoughts about it!