Getting the most out of delegatecall Looking for the code? I’m a blockchain architect and developer at Design is Dead , check us out! A couple of months ago I wrote my first blog post about upgradeable smart contracts on the . We explained that once a smart contract has been deployed onto the blockchain it cannot be changed. Ethereum blockchain Wait? Not being able to upgrade code after launching it? That seems like a bad idea, especially if you’re used to an agile development cycle. And while guaranteed code execution can be a benefit, when there is a bug it is the total opposite. Bugs in smart contracts have caused millions of dollars in losses and even gave birth to Ethereum as we know today, after one of the most popular smart contracts in the early days, the , was found to have a vulnerability that allowed an attacker to drain all funds in the contract ( ). slock.it DAO re-entrancy attack https://medium.com/swlh/the-story-of-the-dao-its-history-and-consequences-71e6a8a551ee First Version , we explored a strategy based on the that was conceived by Monax (now ) before Solc was even released, so it’s pretty old in the ethereum world. This model splits storage and logic into separate contracts and has a registry to keep track of the individual parts. This version becomes expensive to deploy, especially if we instantiate the same contract over and over again. This is similar to instantiating classes in traditional programming but contract deployment on the Ethereum blockchain costs real money, so we don’t want to spend more than necessary. In our last blog post on this subject five-types-model Hyperledger Burrow Proxy Libraries The was okay to start with but wasn’t optimal. With proxy libraries, our base contract is a library already deployed on the blockchain. When we create an instance of this, we will deploy a contract that forwards its calls to the address that is specified. If we want to update some function logic in the library we would redeploy the library and point our contracts to this new library. Even with this strategy, there’s quite a bit of code overhead to make it happen. Eventually, our goal was to limit the code of our instantiated contracts to only one function, a forwarding function. five-types-model Upgradeable V2 A little over a year ago Vitalik released regarding the subject of forwarding contracts. The issue was that pre-metropolis (when the post was written), the output size of forwarded functions could not be dynamic and was restricted to . That issue was fixed in which allows us to properly implement this type of forwarding now. Contract calls are forwarded using a low-level version of (although in solidity 0.5.0, the high-level version also returns data now). Delegatecall forwards a call to another contract and allows that contract to . a Reddit post 4096 bytes Metropolis DELEGATECALL change the storage of the delegator while keeping the original message object Delegatecall isn’t very well documented. The documentation says that it takes the context of the calling contract (message object and storage) and uses that in the forwarded call. One undocumented feature is that if the forwarder has no storage definitions of itself in the contract, it will still assume the definitions of the master contract with its own values after initialization as long as the storage order matches. Let’s make it more clear with a code example (thanks to the guys from for pointing me to this method) Origin Protocol Example For starters, we have a master contract. It has an unsigned integer set in storage called and two functions. One to increment by one, and one to retrieve the variable. count count DummyMaster.sol Next up we have the contract that will serve as the instance of , In the constructor of we set the address of . DummyMaster.sol note that both contracts start with because the contracts need to follow each other’s storage order. address impl Dummy.sol DummyMaster.sol Dummy.sol After compiling, has no ABI that matches DummyMaster, in order to easier interact with the contracts we can write an interface contract that is not deployed. This step isn’t necessary but it’s easier to create the this way by instantiating the interface at the proxy address (see ). Dummy.sol calldata test.js DummyInterface.sol test.js Let’s test our new architecture! First deploy the master, then deploy the proxy a couple of times and pass the master address in the constructor. In our test, we deploy the proxy three times. We can test that each proxy has separate storage, the count in all instances must equal 1 if we were using the same contract everytime the count would be 3. And that’s it, a really light method to write upgradeable smart contracts! One caveat is that transactions to these contracts are slightly more expensive, therefore it’s not a good idea to use this with a monolith contract that holds all the data, like ERC20 token contracts. On the other hand, contracts that are per-user or between a limited set of users, like an escrow, bounty or identity claims registry would greatly benefit from this. The full code can be found on ! Thanks for reading! my Github I’m a blockchain architect and developer at Design is Dead , check us out! Learn smart contract development
Share Your Thoughts