Proxy Contracts
A proxy contract is an intermediary contract that delegates calls to another smart contract known as the 'implementation' contract. When you intend to interact with the underlying 'implementation' contract, you must do so through the proxy.
The proxy contract stores the address of the 'implementation' contract. When a user interacts with the proxy contract, it delegates the call to the 'implementation' contract. Subsequently, the 'implementation' contract executes the requested function and returns the result to the proxy contract, which, in turn, returns the result to the user.
Some benefits of using a proxy contract include:
- Upgrading the implementation contract without changing the proxy contract address, which allows rollback to previous versions of implementation contracts, and contract upgrades wouldn't require contract users to change the contract address that they intend to interact with.
- Deploying a new implementation contract is more gas-efficient than deploying an entirely new contract, and it minimizes the need to update references to the contract's address in dApps.
Proxy Contract Support on Etherscan
This section was adapted from an Etherscan blog article on Medium by @Enigmatic1256
The heuristic involved being that Etherscan considers the contract code, specifically looking for identifiable bytecode patterns associated with well-known proxy contract implementations. For example, specific Solidity assembly code patterns exist in the bytecode of a contract that utilizes the delegateCall
opcode, a low-level function that proxy contracts frequently employ.
If the delegateCall
opcode exists, then the below button will be displayed:
Clicking on the button will load the Proxy Contract verification page. Clicking “Verify” will run the checks to obtain the implementation contract.
If successfully done, we will get a happy green message — Things can still be inaccurate so do let us know if it is the case.
Once saved, returning to the Contract tab of the proxy/storage contract page will display a new “Read as Proxy” and “Write as Proxy” sections, where the ABI used to load these read/write fields are the implementation contract’s ABI.
What if the implementation address was upgraded?
If the proxy contract’s implementation address had been upgraded, just re-run the verification process and the new implementation address will be noted and stored in our database.
Caveats
Naturally, as far as programming heuristics go there are a few caveats:
- Contracts showing “is this a proxy?” may not actually be a proxy contract —An example are contracts relying on libraries which also use the delegateCall opcode to forward storage data for manipulation.
- For custom proxy contracts, we use Parity’s vmtrace to attempt detection of a delegateCall subcall, and retrieve the “to” address involved. Which means a transaction involving the implementation address has to be done prior, therefore would not work on newly deployed contracts/if there is a recent implementation address change. This is highly experimental, and may/may not be retained as a feature.
Limitations of Proxy Support on Etherscan
Always practice caution when interacting with smart contracts on Ethereum. The proxy contract may or may not delegate calls to an external contract as detected, or the delegateCall function may not even be reachable.
Etherscan doesn't automatically verify if the code shown in the 'Read as Proxy/Write as Proxy' tabs is what's actually being executed when interacting with the proxy. As such, potentially malicious implementations could be hidden from plain sight.
The only way to verify this is to carefully check the implementation of the proxy contract and only interact with contracts you know you can trust. Trust, but verify.