Imagine that we have developed a couple of smart contracts and we deploy in a production enviroment. With the pass of the time we look that we need some functions that in the deployed contracts are not.

So beeing imposible to update the deployed contract. What are the best practices to solve this cain of common mistakes without lose the data?

  1. In the new contract call to the old contract functions to recover the data and works with bouth
  2. ...
  3. ..
  4. .

Is a conceptual doubt the scenario is not reall. But I think in if I face with it


It is indeed possible to upgrade existing smart contract, but initial contract needs to explicitly allow this. The idea is that initial smart contract should be able to delegate some or all of his functions to another contract, and also to delegate fallback function as well.

In you need an example, see how delegatable modifier is implemented and used in this smart contract.

Here is modifier code:

modifier delegatable {
  if (delegate == address (0)) {
    require (msg.value == 0); // Non payable if not delegated
  } else {
    assembly {
      // Save owner
      let oldOwner := sload (owner_slot)

      // Save delegate
      let oldDelegate := sload (delegate_slot)

      // Solidity stores address of the beginning of free memory at 0x40
      let buffer := mload (0x40)

      // Copy message call data into buffer
      calldatacopy (buffer, 0, calldatasize)

      // Lets call our delegate
      let result := delegatecall (gas, oldDelegate, buffer, calldatasize, buffer, 0)

      // Check, whether owner was changed
      switch eq (oldOwner, sload (owner_slot))
      case 1 {} // Owner was not changed, fine
      default {revert (0, 0) } // Owner was changed, revert!

      // Check, whether delegate was changed
      switch eq (oldDelegate, sload (delegate_slot))
      case 1 {} // Delegate was not changed, fine
      default {revert (0, 0) } // Delegate was changed, revert!

      // Copy returned value into buffer
      returndatacopy (buffer, 0, returndatasize)

      // Check call status
      switch result
      case 0 { revert (buffer, returndatasize) } // Call failed, revert!
      default { return (buffer, returndatasize) } // Call succeeded, return

You can create a proxy contract that "sends" the transaction to an upgradeable contract. If the proxy contract and upgradeable contract share the same storage structure, the upgradeable contract can update the storage of the proxy. This allows storage to persist across upgrades.

Add the following function to your proxy contract. You can then call any function from the upgradeable contract. Just send the transaction like normal, but use the address of the proxy instead of the upgradeable contract.

function() public payable{
    address target = contractAddress;

        let ptr := mload(0x40)
        calldatacopy(ptr, 0, calldatasize)

        let result := delegatecall(gas, target, ptr, calldatasize, 0, 0)

        let size := returndatasize
        returndatacopy(ptr, 0, size)

        switch result
        case 0 {revert(ptr, size)}
        default {return(ptr,size)}

Your proxy contract should have a global variable named contractAddress. Just change this address to change to a different upgradeable contract.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.