Proxy

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.20;

/// @title Transparent Upgradeable Proxy (EIP-1967)
/// @notice Delegates calls to an implementation; admin can upgrade.
/// @dev Admin cannot call logic functions through proxy (transparent proxy), to avoid confusion with user calls.
contract Proxy {
    bytes32 private constant _IMPLEMENTATION_SLOT = bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);
    bytes32 private constant _ADMIN_SLOT = bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1);

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

    constructor(address logic, address admin_, bytes memory data) payable {
        require(logic != address(0), "Proxy: zero logic");
        require(admin_ != address(0), "Proxy: zero admin");
        _setAdmin(admin_);
        _setImplementation(logic);
        if (data.length > 0) {
            (bool ok, ) = logic.delegatecall(data);
            require(ok, "Proxy: init failed");
        }
    }

    /*///////////////  Admin-only management  ///////////////*/

    /// @notice Return current admin.
    function admin() public view returns (address) {
        return _admin();
    }

    /// @notice Return current implementation.
    function implementation() public view returns (address) {
        return _implementation();
    }

    /// @notice Admin-only: upgrade implementation.
    function upgradeTo(address newImplementation) external ifAdmin {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /// @notice Admin-only: upgrade and then call (e.g., initialize).
    function upgradeToAndCall(address newImplementation, bytes calldata data)
        external
        payable
        ifAdmin
    {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
        (bool ok, ) = newImplementation.delegatecall(data);
        require(ok, "Proxy: delegate init failed");
    }

    /// @notice Admin-only: change admin.
    function changeAdmin(address newAdmin) external ifAdmin {
        require(newAdmin != address(0), "Proxy: zero newAdmin");
        emit AdminChanged(_admin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /// @dev Admin gating: if caller is admin, run admin-view; otherwise delegate like normal user.
    modifier ifAdmin() {
        if (msg.sender == _admin()) {
            _;
        } else {
            _delegate(_implementation());
        }
    }

    /*////////////////////  Fallback & Receive  ////////////////////*/

    fallback() external payable {
        _delegate(_implementation());
    }

    receive() external payable {
        _delegate(_implementation());
    }

    /*////////////////////  Internal utils  ////////////////////*/

    function _implementation() internal view returns (address impl) {
        bytes32 slot = _IMPLEMENTATION_SLOT;
        assembly {
            impl := sload(slot)
        }
    }

    function _admin() internal view returns (address adm) {
        bytes32 slot = _ADMIN_SLOT;
        assembly {
            adm := sload(slot)
        }
    }

    function _setImplementation(address newImpl) internal {
        require(newImpl.code.length > 0, "Proxy: impl not a contract");
        bytes32 slot = _IMPLEMENTATION_SLOT;
        assembly {
            sstore(slot, newImpl)
        }
    }

    function _setAdmin(address newAdmin) internal {
        bytes32 slot = _ADMIN_SLOT;
        assembly {
            sstore(slot, newAdmin)
        }
    }

    /// @dev Delegate helper (no return to Solidity; returns/reverts using assembly).
    function _delegate(address impl) internal {
        assembly {
            // copy calldata to memory
            calldatacopy(0, 0, calldatasize())
            // delegatecall to implementation
            let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)
            // copy returndata
            returndatacopy(0, 0, returndatasize())
            // bubble
            switch result
                case 0 {
                    revert(0, returndatasize())
                }
                default {
                    return(0, returndatasize())
                }
        }
    }
}

Tags:
Proxy, Upgradeable|addr:0x85a52b6eed2f38452b33c275a5354c3442e9a2c9|verified:true|block:23623596|tx:0x52b8ff2654dcd007f713f1236714caabcc85fb2a412cbb986ff9dfe82dbc0759|first_check:1761041911

Submitted on: 2025-10-21 12:18:33

Comments

Log in to comment.

No comments yet.