Skip to content

Instantly share code, notes, and snippets.

@liamzebedee
Last active January 21, 2023 05:32
Show Gist options
  • Select an option

  • Save liamzebedee/45b8e5e93b4e07db0dc9f4273c6d69e6 to your computer and use it in GitHub Desktop.

Select an option

Save liamzebedee/45b8e5e93b4e07db0dc9f4273c6d69e6 to your computer and use it in GitHub Desktop.
A high-quality Ethereum proxy in under 100 lines of code
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.13;
// An implementation of a proxy.
// The proxy forwards all calls to the implementation.
// The proxy has an admin.
contract ProxyStorage {
struct ProxyStore {
address admin;
address implementation;
bool init;
}
bytes32 constant STORE_SLOT = bytes32(uint(keccak256("eth.nakamofo.proxy")) - 1);
function _store() internal pure returns (ProxyStore storage store) {
bytes32 s = STORE_SLOT;
assembly {
store.slot := s
}
}
}
contract Proxy is
ProxyStorage
{
constructor(address _resolver) {
_setProxyAdmin(msg.sender);
}
event Upgraded(address indexed implementation);
event AdminChanged(address previousAdmin, address newAdmin);
function proxyAdmin() public view returns (address) {
return _store().admin;
}
function implementation() public view returns (address) {
return _store().implementation;
}
function setProxyAdmin(address _admin) public {
require(msg.sender == _store().admin, "ERR_UNAUTHORISED");
_setProxyAdmin(_admin);
}
function _setProxyAdmin(address _admin) internal {
emit AdminChanged(_store().admin, _admin);
_store().admin = _admin;
}
function upgrade(address _implementation) public {
require(msg.sender == _store().admin, "ERR_UNAUTHORISED");
emit Upgraded(_implementation);
_store().implementation = _implementation;
}
/// @dev Fallback function forwards all transactions and returns all received return data.
function _fallback() internal {
address _implementation = _store().implementation;
assembly {
calldatacopy(0, 0, calldatasize())
let success := delegatecall(not(0), _implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch success
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev Fallback function that delegates calls to the masterCopy.
* Runs when no other function in the contract matches the call data.
*/
fallback () external payable {
_fallback();
}
/**
* @dev Fallback function that receives ether and delegates calls to masterCopy.
* Runs when call data is empty.
*/
receive () external payable {
_fallback();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment