0

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

0

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
    }
  }
}
| improve this answer | |
0

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;

    assembly{
        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.

| improve this answer | |
0

There are a number of approaches using which you can upgrade a Contract1 to Contract2, keeping its state(data & balance) with the same address as before.

How does this work? A way is to use a proxy contract with a fallback function where each method call/trx is delegated to the implementation contract (which contains all the logic). enter image description here

A delegate call is similar to a regular call, except that all code is executed in the context of the caller (proxy), not of the callee (implementation). Because of this, a transfer in the implementation contract’s code will transfer the proxy’s balance, and any reads or writes to the contract storage will read or write from the proxy’s storage.

In this approach, users only interact with the proxy contract and we can change the implementation contract while keeping the same proxy contract.

enter image description here

The fallback function will execute on any request, redirecting the request to the implementation and returning the resulting value (using opcodes).

This was a basic explanation which is enough for us to work with upgradeable contracts. In case, you want to dig deep into proxy contract code and different proxy patterns, then check out these posts.

How can I write upgradable smart contracts?

OpenZeppelin provides awesome CLI tools & JS Libraries that take care of all the above complex proxy contracts, linking it to implementation (logic) contract & managing all the contracts you deploy using the CLI for upgradability, out-of-the-box.

The only thing you need to do is to write your contracts, and use OpenZeppelin CLI or Libraries to deploy the contracts.

NOTE: There are a few Limitations that you should be aware of, in terms of how you need to write your contracts and how you should upgrade them. There are also a number of workarounds these limitations in this post.

| improve this answer | |

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