🌱
Dev Compendium
  • Ethereum
    • Solidity
      • EVM
      • Architecture
      • Execution Context
      • Transactions
      • Gas
      • Calldata, Memory & Storage
      • Gas Optimisation
      • Function Declarations
      • receive() & fallback()
      • CALL vs. DELEGATE CALL
    • Yul
      • Introduction
      • Types
      • Basic Operations
      • Storage
      • Memory
        • Arrays
        • Structs
        • Tuples, revert, keccak256
        • Logs and Events
        • Gotchas
        • abi.encode
      • Calldata
        • External Calls
        • Dynamic Length Inputs
        • Transferring Value
        • Receiving Contract Calls
      • Contracts in Yul
      • Other Yul Functions
    • Foundry
    • Security
      • Common Vulnerabilities
      • Best Practices
      • Development Workflow
      • Contract Migration
    • Auditing Tools
      • Slither
      • Mythril
      • Fuzzing
    • Upgradable Contracts
      • Upgrade Patterns
      • ERC-1967 Implementation
      • Deployment
    • MEV
    • Tooling
      • Chainlink
      • IPFS
      • Radicle
    • Frontend
      • Contract Hooks
      • Wallet Connection
        • wagmi.sh
        • Rainbow Kit
      • thirdweb
    • Protocol Research
      • Uniswap v2
      • Uniswap v3
      • Curve
      • GMX
  • Starkware
    • Fundamentals
    • Account Abstraction
    • Universal Deployer
    • Cairo 1.0
    • starknet.js
    • Security Model
  • Zero Knowledge
    • Group Theory
    • ECDSA
  • Rust
    • Basic Operations
    • Set up
    • Primitives
    • Control Flow
    • Mutability & Shadowing
    • Adding Behavior
    • Lifetimes
    • Std Library
  • SUI
    • Architecture
    • Consensus Mechanism
    • Local Node Setup
    • Sui Client CLI
    • Move Contracts
      • Move
      • Move.toml
      • Move.lock
      • Accessing Time in Sui Move
      • Set up Development Framework
      • Debug & Publish
      • Package Upgrades
      • Sui Move Library
      • Difference from Core Move
    • Object Programming
      • Object Basics
      • Using Objects
      • Immutable Objects
      • Object Wrapping
      • Dynamic Fields
      • Collections
      • Unit Testing
      • Deployment with CLI
  • NEAR
    • Architecture
    • Contract Standards
      • Fungible Token (NEP-141)
      • Non-Fungible Token (NEP-171)
      • Storage Management (NEP-145)
      • Events (NEP-297)
      • Meta-Transactions
    • Rust Contracts
      • Development Workflow
      • Smart Contract Layout
      • Storage Management
      • Events & Meta-transactions
      • Method Types
      • Upgrading Contracts
      • Unit Testing
    • NEAR Libraries
    • Environment Variables
    • Serialisation
    • Security Concepts
    • Collections
    • JS SDK
Powered by GitBook
On this page
  • Transparent Proxies
  • Universal Upgradeable Proxy Standard (UUPS)
  1. Ethereum
  2. Upgradable Contracts

Upgrade Patterns

PreviousUpgradable ContractsNextERC-1967 Implementation

Last updated 2 years ago

Transparent Proxies

Since all function calls in Solidity are identified by the function selector, there is a low but non-zero possibility of an implementation contract having a function that has the same 4-byte identifier as the proxy’s upgrade function. This could cause an admin to inadvertently upgrade a proxy to a random address while attempting to call a completely different function provided by the implementation.

This issue can be solved by setting up such that the admin can only call upgrade management functions, and all other users can only call functions of the implementation contract.

The transparent pattern has a downside: gas cost. Each call requires an additional read from storage to load the admin address. The contract itself is also relatively expensive to deploy compared to other proxies, at over 700k gas.

Universal Upgradeable Proxy Standard (UUPS)

As an alternative to transparent proxies, defines the universal upgradeable proxy standard, or UUPS for short. This standard uses the same delegate call pattern, but places upgrade logic in the implementation contract instead of the proxy itself.

Since the proxy uses delegate calls, the implementation contract always writes to the proxy’s storage instead of its own. The implementation address itself is kept in the proxy’s storage. UUPS proposes that all implementation contracts extend from a base proxiable contract:

contract UUPSProxy {
    address implementation;
    
    fallback() external payable {
        implementation.delegatecall.value(msg.value)(msg.data);
    }
}
abstract contract UUPSProxiable {
    address implementation;
    address admin;
    
    function upgrade(address newImplementation) external {
        require(msg.sender == admin);
        implementation = newImplementation;
    }
https://blog.openzeppelin.com/the-transparent-proxy-pattern/
EIP1822