14

I was looking at the recent FE badger DAO exploit and this Twitter thread in it https://twitter.com/CryptoCatVC/status/1466380960648380419?s=20

One piece of advice the author gives before signing a metamask transaction is to inspect the etherscan address of the contract and see if it is a proxy contract.

What exactly is a proxy contract? How does one check if a contract is a proxy contract? What are the risks involved with interacting with a proxy contract?

2 Answers 2

19

A proxy contract is a contract which delegates calls to another contract. To interact with the actual contract you have to go through the proxy, and the proxy knows which contract to delegate the call to (the target).

A proxy pattern is used when you want upgradability for your contracts. This way the proxy contract stays immutable, but you can deploy a new contract behind the proxy contract - simply change the target address inside the proxy contract.

Therefore it's a bit dangerous to use a proxy contract, since there are no guarantees that the underlying (target) contract hasn't been changed to a malicious one. There is no strict definition on how to detect a proxy contract, but basically it's anything that delegates the functionality to another contract. You have to analyze the source code to be able to decide.

2
  • 1
    You can see if a contract uses a proxy by looking on EtherScan. See my answer. Jun 16, 2022 at 23:32
  • You can use a proxy because you just want to clone a contract many times. You might not want to upgrade the contract, but you save gas by keeping the functionality in the same contract while the state variables live in the clones. This is what Uniswap does, for example. Look at the OpenZeppelin's Clones library.
    – Jose4Linux
    Aug 22, 2022 at 11:48
6

Proxies (or "diamonds", which is just a name for a specific proxy system specified as an EIP) allow part or all of a contract to be swapped out at any time, without changing the address of the primary entry point for the contract. The entry point simply stores the address of the latest implementation (which may be changed by the contract owner), and then it forwards any function calls to the address of the latest implementation. Proxies were developed because contract deployment is irreversible: the code of a deployed contract can never be changed. But contract storage can be changed. So at the deployment address, the proxy code is deployed, along with the forwarding address of the actual contract you want users to call. Then any function call to the proxy address will just be forwarded to the actual target contract. There are a couple more functions in the proxy contract that allow the owner of the contract to update the forwarding address. This is how the proxied "real" contract can be updated.

Proxies are less safe non-proxied contracts if you don't trust the contract owners (since the owners can swap out the implementation at any time, screwing with their users however they want), but they are more safe than non-proxied contracts if you do trust the contract owners (since the owners can fix bugs at any time).

If a security bug is found in a contract implementation, and it was not deployed to work through a proxy, then the only way to fix the security bug is to:

  1. Freeze all activity on the buggy contract, if your API even has a call to accomplish that (but adding that sort of API will reduce user confidence in your contract if they don't trust you).
  2. Fix the bug to create a new bug-free version of the contract.
  3. Make a complete copy of the data structures of the old contract, reversing any damaging changes to account balances etc. that were made by hackers, if the vulnerability was actively exploited. (Note that this may cause a ripple effect of bugs on other contracts, such as exchanges, since they expect that the "rug won't be pulled out from under them", i.e. that account balances etc. will not suddenly change in unexpected ways. This issue is true even for proxied contracts, if you try to fix any damage done, by overriding behavior directly.)
  4. Deploy the fixed data structures along with the new bug-free version of the code (this can be very expensive if the old contract has grown a lot in its storage requirements over time).
  5. Instruct your users to use the new copy of the contract, at the new deployment address (who knows if you will even be able to reach all users who need to know).
  6. Ask your old contract to SELFDESTRUCT, if you even have an API to do that (but adding that sort of API will also reduce user confidence in your contract if they don't trust you).
  7. Hope that all other contracts that need to call your contract (such as exchanges) see your notice that your contract address has changed.
  8. Hope that people trust that the newly deployed contract is the official replacement for the buggy old contract (scammers could probably impersonate the authors of the buggy contract to claim there was a new bugfixed version, and take over the ecosystem).

So you can probably see, proxied contracts are the way to go if you are deploying a contract as a trustworthy/trusted individual or organization, because the above alternative is pretty terrible.

On the flip side, whether or not you are not a trustworthy/trusted individual or organization, if you deploy without a proxy, the chance of an exploitable vulnerability being found in the contract is fairly high, and that may undermine users' confidence in your contract. Therefore not deploying with a proxy may be more anxiety-inducing for users than deploying with a proxy!

If you are not a trustworthy/trusted individual or organization, and you want to avoid a dubious response to deploying your contract via a proxy, then you need to invest in an unbiased security audit of your contract before deploying it. But these can run anywhere from tens to hundreds of thousands of dollars.

If you do get a security audit, Etherscan has a way of submitting the URL to the audit results, which can then be officially associated with your contract, so that people can see it's trustworthy. Although even if you deploy an audited contract, but you deploy with a proxy, there's nothing stopping you from coming back later and swapping out the implementation with one that contains some nefarious bug. (You will lose your Etherscan source verification if you do that though, since the proxied contract will no longer have the same hashcode as the old one you verified with source, unless you submit the nefarious source for verification.)

EtherScan can detect whether a contract is proxied, in many circumstances:

https://medium.com/etherscan-blog/and-finally-proxy-contract-support-on-etherscan-693e3da0714b

https://etherscan.io/proxyContractChecker

When viewing a contract on EtherScan, under the "Contract" tab, if Etherscan knows the contract is proxied, then you will have not just "Read Contract" and "Write Contract", but also "Read Contract via Proxy" and "Write Contract via Proxy" or similar.

If the proxied code has been updated, Etherscan will show you the contract address for the previous version(s) of the code, so that users can examine all versions for changes.

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.