2

I have a smart contract deployed on ethereum network, I might have to change it according to future requirement changes, as they are immutable, then to which extent I would be able make changes in my smart contract?

let's just say I wanna add one or more new variable(s) into my smart contract is it even possible?

Would proxy method let me add another variable in my smart contract? How much changes can be made using proxy method?

6
  • the way to go is to replace it with a new version and update your dApp with new address
    – Nulik
    Commented Jul 27, 2021 at 16:41
  • @Nulik which means my previous contract after update would be of no use? Commented Jul 28, 2021 at 8:19
  • exactly, that's why they implement pausable and these kind of flag to shut down the execution
    – Nulik
    Commented Jul 28, 2021 at 10:53
  • @Nulik one more thing, what would be upgradeable scenarios if I use ERC-1155 standard? Commented Jul 29, 2021 at 7:44
  • that doesn't matter, the upgrade mechanism is the same for all. Check for example Uniswap. They have version v2 running, and now they released version 3. Both are running because therea are many users. You only want to shutdown the previous contract when you have assets in it, like Tokens, in that case you do a Transfer to migrate tokens
    – Nulik
    Commented Jul 29, 2021 at 11:54

1 Answer 1

1

There are quite a few caveats to Upgradable Smart contracts and various approaches.

In the case of the proxy method you are referring to the Proxy Smart contract interacts with a Logic Smart contract.

The contract state is stored in the Proxy Contract and Logic is executed via the Logic contract. When Upgrades are performed it is referring to creating a different logic contract to be associated with the Proxy Contract.

The relationship between the Proxy contract and the Logical one with respect to Upgradability is made possible via EVM’s opcode delegatecall. This executes the callee’s code in the context of the caller’s state.

The logic contract controls the proxy’s state and the logic contract’s state is meaningless. Thus, the proxy doesn’t only forward transactions to and from the logic contract, but also represents the pair’s state. The state is in the proxy and the logic is in the particular implementation that the proxy points to.

[1] https://docs.soliditylang.org/en/v0.8.6/introduction-to-smart-contracts.html?highlight=Delegatecall#delegatecall-callcode-and-libraries

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

[2] https://docs.openzeppelin.com/learn/upgrading-smart-contracts#how-upgrades-work

Another important consideration is the possibility of Storage Collisions which has solutions in using an unstructured storage for the initial deployment and then appending the storage hierarchy in new versions.

[3] https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#the-constructor-caveat

For Upgradable Smart Contracts you cannot use a constructor because in Solidity, code that is inside a constructor or part of a global variable declaration is not part of a deployed contract’s runtime bytecode. Constructor code is executed only once, when the contract instance is deployed. As a consequence of this, the code within a logic contract’s constructor will never be executed in the context of the proxy’s state. To rephrase, proxies are completely oblivious to the existence of constructors. It’s simply as if they weren’t there for the proxy.

[3] https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#the-constructor-caveat

The solution to this is to to implement an initialization function instead of a constructor. Moreover if you are using OpenZeppelin it is imperative that you use the openzeppelin-contracts-upgradeable as all subcontracts will have to have this structure as well.

[4] https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable

This caveat further applies to the initial values on field declarations which are equivalent to constructors i.e.

contract MyContract {
    uint256 public hasInitialValue = 42; // equivalent to setting in the constructor
}

This should be set as

contract MyContract is Initializable {
    uint256 public hasInitialValue;

    function initialize() public initializer {
        hasInitialValue = 42; // set initial value in initializer
    }
}

[5] https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#avoid-initial-values-in-field-declarations

Finally there is the also the consideration of function clash (same function name in Proxy and Logic). This is can be solved using the transparent proxy pattern

[6] https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#transparent-proxies-and-function-clashes

Unavoidably however clashing can also happen among functions with different name. This is because every contracts ABI is identified - at a bytecode level - by a 4-byte identifier. With only 4-bytes - it's possible that two functions with different names may have the same identifier. Solidity compiler tracks this within the same contract - however in the case of proxy contracts -> logic contract the compiler cannot track it because its two separate smart contracts.

[7] https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357

So the overall summary here is that upgradeable smart contract instances (proxies) work by delegating all calls to a logic smart contract. Made possible by the low level call delegatecall. Constructors cannot be used as they are not part of a deployed smart contract’s runtime bytecode and thus the code within a logic contract’s constructor will never be executed in the context of the proxy’s state. The latter as related to constructors is likewise true for initial values on field declarations.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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