ERC1967Proxy

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract ERC1967Proxy {
    // impl slot = keccak256("eip1967.proxy.implementation") - 1
    bytes32 private constant _IMPLEMENTATION_SLOT =
        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
    // admin slot = keccak256("eip1967.proxy.admin") - 1
    bytes32 private constant _ADMIN_SLOT =
        0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    event Upgraded(address indexed implementation);
    event AdminChanged(address indexed previousAdmin, address indexed newAdmin);

    // <<< Simpler constructor: pass impl + owner. It will call initialize(owner) >>>
    constructor(address impl_, address owner_) {
        require(impl_.code.length > 0, "no impl");
        require(owner_ != address(0), "zero owner");
        _setAdmin(msg.sender);
        _setImplementation(impl_);

        (bool ok, bytes memory ret) = impl_.delegatecall(
            abi.encodeWithSignature("initialize(address)", owner_)
        );
        if (!ok) {
            if (ret.length > 0) assembly { revert(add(ret, 32), mload(ret)) }
            revert("init failed");
        }
    }

    // --- admin API ---
    function admin() external view returns (address a) { assembly { a := sload(_ADMIN_SLOT) } }
    function implementation() external view returns (address impl) { assembly { impl := sload(_IMPLEMENTATION_SLOT) } }

    function changeAdmin(address newAdmin) external {
        address a; assembly { a := sload(_ADMIN_SLOT) }
        require(msg.sender == a, "!admin");
        require(newAdmin != address(0), "zero");
        _setAdmin(newAdmin);
        emit AdminChanged(a, newAdmin);
    }

    function upgradeTo(address newImplementation) external {
        address a; assembly { a := sload(_ADMIN_SLOT) }
        require(msg.sender == a, "!admin");
        require(newImplementation.code.length > 0, "no impl");
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    // --- fallback ---
    fallback() external payable { _delegate(); }
    receive() external payable { _delegate(); }

    // --- internals ---
    function _setImplementation(address newImpl) private {
        assembly { sstore(_IMPLEMENTATION_SLOT, newImpl) }
    }
    function _setAdmin(address newAdmin) private {
        assembly { sstore(_ADMIN_SLOT, newAdmin) }
    }
    function _delegate() private {
        address impl; assembly { impl := sload(_IMPLEMENTATION_SLOT) }
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(0, 0, size)
            switch result
            case 0 { revert(0, size) }
            default { return(0, size) }
        }
    }
}

Tags:
Proxy, Upgradeable|addr:0xf86b5c6a8c01129a45ae9647a423566d00db9c4d|verified:true|block:23638746|tx:0x589d385b80859b44a689024a23e82f6af43e1a78b10daa88197bdae9a1d4ded3|first_check:1761304014

Submitted on: 2025-10-24 13:06:57

Comments

Log in to comment.

No comments yet.