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) }
}
}
}
Submitted on: 2025-10-24 13:06:57
Comments
Log in to comment.
No comments yet.