Created
December 13, 2021 12:34
-
-
Save td-bn/d455fb780991c239bd26e80436c75833 to your computer and use it in GitHub Desktop.
Simple Proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./Registry.sol"; | |
contract Logic { | |
bytes32 constant SUPEROWNER = keccak256("superowner"); | |
bytes32 constant OWNER = keccak256("owner"); | |
uint public value; | |
address public registry; | |
bool locked = false; | |
modifier onlyOwner() { | |
require(Registry(registry).hasRole(OWNER, msg.sender), "!owner"); | |
_; | |
} | |
modifier nonReentrant() { | |
require(!locked, "Reentrant call"); | |
locked = true; | |
_; | |
locked = false; | |
} | |
function initialize(address _reg) public { | |
registry = _reg; | |
} | |
function setValue(uint _val) public onlyOwner nonReentrant { | |
value += _val; | |
} | |
function getValue() public onlyOwner nonReentrant returns (uint) { | |
return value; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./Registry.sol"; | |
contract Logic2 { | |
bytes32 constant SUPEROWNER = keccak256("superowner"); | |
bytes32 constant OWNER = keccak256("owner"); | |
uint public value; | |
address public registry; | |
bool locked = false; | |
event SetValue(uint); | |
event GotValue(uint); | |
modifier onlyOwner() { | |
require(Registry(registry).hasRole(OWNER, msg.sender), "!owner"); | |
_; | |
} | |
modifier nonReentrant() { | |
require(!locked, "Reentrant call"); | |
locked = true; | |
_; | |
locked = false; | |
} | |
function initialize(address _reg) public { | |
registry = _reg; | |
} | |
function setValue(uint _val) public onlyOwner nonReentrant { | |
value += _val; | |
emit SetValue(value); | |
} | |
function getValue() public onlyOwner nonReentrant returns (uint) { | |
emit GotValue(value); | |
return value; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
// For debugging | |
import "hardhat/console.sol"; | |
import "./Registry.sol"; | |
contract Proxy { | |
bytes32 constant IMPL_SLOT = keccak256("my.impl.slot"); | |
bytes32 constant SUPEROWNER = keccak256("superowner"); | |
constructor(address impl, address reg) { | |
(bool success, ) = impl.delegatecall( | |
abi.encodeWithSignature("initialize(address)", reg) | |
); | |
require(success, "Failed to initialize"); | |
_setImpl(impl); | |
} | |
function changeImpl(address _newImpl) public { | |
address reg; | |
assembly { | |
reg := sload(1) | |
} | |
require(Registry(reg).hasRole(SUPEROWNER, msg.sender), "!authorized"); | |
_setImpl(_newImpl); | |
} | |
function getImpl() public view returns (address) { | |
bytes32 slot = IMPL_SLOT; | |
address impl; | |
assembly { | |
impl := sload(slot) | |
} | |
return impl; | |
} | |
function _setImpl(address impl) internal { | |
bytes32 slot = IMPL_SLOT; | |
assembly { | |
sstore(slot, impl) | |
} | |
} | |
fallback() external payable { | |
address implementation = getImpl(); | |
console.log("implementation:", implementation); | |
assembly { | |
calldatacopy(0, 0, calldatasize()) | |
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) | |
returndatacopy(0, 0, returndatasize()) | |
switch result | |
case 0 { | |
revert(0, returndatasize()) | |
} | |
default { | |
return(0, returndatasize()) | |
} | |
} | |
} | |
receive() external payable { | |
} | |
// For help with debugging | |
function keccak(string memory str) public pure returns (bytes32) { | |
return keccak256(abi.encodePacked(str)); | |
} | |
function getStorageAtSlot(uint i) public view returns (bytes32) { | |
bytes32 data; | |
assembly { | |
data := sload(i) | |
} | |
return data; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/access/AccessControl.sol"; | |
// For debugging | |
import "hardhat/console.sol"; | |
contract Registry is AccessControl { | |
bytes32 constant SUPEROWNER = keccak256("superowner"); | |
bytes32 constant OWNER = keccak256("owner"); | |
constructor() { | |
_grantRole(SUPEROWNER, msg.sender); | |
} | |
function addOwner(address _owner) public { | |
require(hasRole(SUPEROWNER, msg.sender), "!authorized"); | |
_grantRole(OWNER, _owner); | |
} | |
function removeOwner(address _owner) public { | |
require(hasRole(SUPEROWNER, msg.sender), "!authorized"); | |
_revokeRole(OWNER, _owner); | |
} | |
function transferOwner(address _newOwner) public { | |
require(hasRole(OWNER, msg.sender), "!authorized"); | |
_revokeRole(OWNER, msg.sender); | |
_grantRole(OWNER, _newOwner); | |
} | |
function renounceOwner() public { | |
require(hasRole(OWNER, msg.sender), "!authorized"); | |
_revokeRole(OWNER, msg.sender); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
// For debugging | |
import "hardhat/console.sol"; | |
contract Test { | |
address public proxy; | |
function setProxy(address _proxy) public { | |
proxy = _proxy; | |
} | |
function testSetValue(uint _val) public { | |
(bool success,) = proxy.call( | |
abi.encodeWithSignature("setValue(uint256)", _val) | |
); | |
require(success, "Call through proxy failed!"); | |
} | |
function testGetValue() public returns(uint) { | |
(bool success, bytes memory data) = proxy.call( | |
abi.encodeWithSignature("getValue()") | |
); | |
require(success, "Call through proxy failed!"); | |
uint ret; | |
(ret) = abi.decode(data, (uint256)); | |
return ret; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment