Skip to content

Proxies and Upgradeable Code

Proxies are a common tool to allow for smart contract code to receive upgrades. A proxy contract acts as a pointer to a logic contract using delegatecall, and the logic contract contains the implementation logic. If the proxy contract is modified to point to a different logic contract address, the implementation logic is changed.

Other resources:

1. Is the UUPS proxy initialized?

Incorrect

No

Correct

Yes

Explanation

An uninitialized proxy can be initialized by anyone. The user that calls the initialize function is granted special privileges for the proxy contract.

Links

2. Does the logic contract behind the proxy contain selfdestruct?

Incorrect

Yes

Correct

No, selfdestruct is not found in the contracts or the contract is not a logic contract behind a proxy contract

Explanation

If the logic contract behind a proxy contains selfdestruct, the proxy can be deleted, which can cause a denial of service. If a metamorphic contract created with CREATE2 contains selfdestruct, then the contract code can be replaced in a similar way to upgrading code behind a proxy.

Links

3. Is the contract (not necessarily a proxy contract) created with CREATE2 or CREATE3 and the contract contains selfdestruct?

Incorrect

Yes

Correct

No, selfdestruct is not found in the contracts or the contract was not created with CREATE2 or CREATE3

Explanation

A CREATE2 or CREATE3 contract that contains selfdestruct can be destroyed and replaced with a new contract at the same address. If a metamorphic contract created with CREATE2 contains selfdestruct, then the contract code can be replaced in a similar way to upgrading code behind a proxy.

Links

4. Does the upgraded logic contract have the same state variable layout as the contract it replaces?

Incorrect

No

Correct

Yes, new state variables are only appended to the list of existing state variables. Even better, the new state variables are filling slots that were already reserved using a pattern like OpenZeppelin contact's storage gap.

Explanation

If the storage variable layout is changed, a storage collision can happen where the variable names in the upgraded contract to not match the variables that are stored in the corresponding storage slots. The storage layout should always consider inheritance, so flattening the contracts to more easily view the storage variables can sometimes be a useful manual approach. Automated tools can also reveal the storage layout of a contract and help verify that no storage collision happens as a result of a contract upgrade.

Links