// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
pragma abicoder v2;
contract Proxy {
// EIP1967
// bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
bytes32 private constant adminPosition = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
// EIP1967
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 private constant implementationPosition =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
// EIP1967
event AdminChanged(address previousAdmin, address newAdmin);
event Upgraded(address indexed implementation);
constructor(address _implementation) {
_setAdmin(address(0), msg.sender);
setImplementation(_implementation);
}
function implementation() public view returns (address _implementation) {
assembly {
_implementation := sload(implementationPosition)
}
}
function setImplementation(address _implementation) public {
require(msg.sender == admin(), 'PX00');
require(_implementation != implementation(), 'PX01');
require(_implementation != address(0), 'PX02');
assembly {
sstore(implementationPosition, _implementation)
}
emit Upgraded(_implementation);
}
function admin() public view returns (address _admin) {
assembly {
_admin := sload(adminPosition)
}
}
function setAdmin(address _admin) external {
address currentAdmin = admin();
require(msg.sender == currentAdmin, 'PX00');
require(_admin != currentAdmin, 'PX01');
require(_admin != address(0), 'PX02');
_setAdmin(currentAdmin, _admin);
}
function _setAdmin(address currentAdmin, address newAdmin) internal {
assembly {
sstore(adminPosition, newAdmin)
}
emit AdminChanged(currentAdmin, newAdmin);
}
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal {
address _implementation = implementation();
assembly {
// Copy msg.data.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
fallback() external payable {
_fallback();
}
receive() external payable {
_fallback();
}
}
{
"compilationTarget": {
"contracts/Proxy.sol": "Proxy"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_implementation","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"_admin","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"_implementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_implementation","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]