Proxy Pattern
The proxy pattern is a smart contract architecture that enables upgradeability by separating a contract's storage (proxy) from its logic (implementation), using delegatecall to forward calls.
In Depth
Proxy patterns allow smart contracts to be upgraded after deployment by splitting the system into a proxy contract (which holds state and receives calls) and an implementation contract (which contains the logic). The proxy uses Solidity's delegatecall to execute the implementation's code in the context of the proxy's storage. Common variants include the transparent proxy (where admin and user calls are handled differently), UUPS (where upgrade logic lives in the implementation), and beacon proxies (where multiple proxies share a single upgradeable implementation pointer). Proxy patterns introduce unique security risks including storage collision between proxy and implementation, uninitialized implementation contracts, and function selector clashes, making them a critical focus area for audits.
Frequently Asked Questions
What is the proxy pattern in smart contracts?
The proxy pattern separates a contract's storage (proxy) from its logic (implementation). The proxy forwards calls to the implementation using delegatecall, executing the logic in the proxy's storage context. This enables upgrading the logic without losing stored data or changing the contract address.
What are the differences between transparent, UUPS, and beacon proxies?
Transparent proxies route admin calls (like upgrades) differently from user calls, adding gas overhead. UUPS proxies move the upgrade function into the implementation, reducing gas costs but requiring the implementation to include upgrade logic. Beacon proxies let multiple proxies share a single implementation pointer, enabling atomic upgrades of many contracts at once.
What security risks do proxy patterns introduce?
Key risks include storage layout collisions between proxy and implementation, uninitialized implementation contracts that attackers can take over, function selector clashes, and incorrect upgrade authorization. These issues require careful auditing and invariant testing to catch.