Skip to content

iampukar/minimal-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Minimal Proxy Contract (EIP-1967)

Disclaimer

This repository contains a minimal proxy contract that implements EIP-1967 storage slots.
🚨 This contract is NOT intended for production use—it is purely for educational and referential purposes.


Overview

This repository showcases the implementation of an upgradeable proxy contract that follows EIP-1967: Standard Proxy Storage Slots.
It leverages OpenZeppelin's delegatecall approach using low-level assembly for efficiency.

Features

  • Minimalistic proxy contract structure
  • EIP-1967 standard slots for admin and implementation
  • Delegatecall-based execution flow
  • Admin-controlled upgradability
  • OpenZeppelin-inspired assembly implementation

Understanding Proxies & EIP-1967

🔹 What is a Proxy Contract?

A proxy contract is a smart contract that delegates calls to an implementation contract.
This allows upgradability, meaning the logic can change without modifying the storage.

🔹 EIP-1967: Why Use Standard Storage Slots?

  • Prevents storage collision between proxy and implementation contracts.
  • Defines a predictable location for storing implementation and admin addresses.
  • Ensures compatibility across different upgradeable patterns.

EIP-1967 Storage Slots Used:

Slot Name Value
IMPLEMENTATION_SLOT keccak256("eip1967.proxy.implementation") - 1
ADMIN_SLOT keccak256("eip1967.proxy.admin") - 1

🔗 Reference: EIP-1967


⚙️ How It Works

1️⃣ Deploy the Proxy Contract

  • The proxy contract does not contain logic but forwards calls via delegatecall().
  • It stores the implementation contract address in the EIP-1967 slot.

2️⃣ Upgrade the Implementation

  • The admin can call upgradeTo(newImplementation).
  • The proxy updates the implementation contract address.
  • Storage remains unchanged, but the contract logic is updated.

3️⃣ Calls are Forwarded via delegatecall()

  • Any function calls go to _delegate(), executing them in the implementation contract's context.

🛠️ OpenZeppelin & Assembly Usage

🔹 OpenZeppelin Low-Level Assembly

This contract uses inline assembly (delegatecall) from OpenZeppelin's Proxy.sol.

assembly {
    calldatacopy(0, 0, calldatasize())
    let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
    returndatacopy(0, 0, returndatasize())

    switch result
    case 0 { revert(0, returndatasize()) }
    default { return(0, returndatasize()) }
}

About

a lightweight minimal proxy contract

Topics

Resources

Stars

Watchers

Forks