Last active
November 4, 2021 14:49
-
-
Save td-bn/2849d9a09aa997989e838e3b269144e9 to your computer and use it in GitHub Desktop.
Proxy contracts gist
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.7.0; | |
contract Logic { | |
event Added(uint256 result); | |
event Fallback(); | |
function add(uint256 a, uint256 b) external returns (uint256 result) { | |
result = a +b; | |
emit Added(result); | |
} | |
fallback() external { | |
emit Fallback(); | |
} | |
} |
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.7.0; | |
abstract contract Proxy { | |
fallback() external payable virtual { | |
_fallback(); | |
} | |
function _fallback() internal virtual { | |
_beforeFallback(); | |
_delegate(_implementation()); | |
} | |
function _delegate(address implementation) internal virtual { | |
assembly { | |
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 | |
case 0 { revert(0, returndatasize()) } | |
default { return(0, returndatasize()) } | |
} | |
} | |
function _implementation() internal view virtual returns(address); | |
function _beforeFallback() internal virtual { | |
} | |
} |
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.7.0; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/access/Ownable.sol"; | |
import "./TransparentUpgradableProxy.sol"; | |
contract ProxyAdmin is Ownable { | |
function getProxyImplementation(TransparentUpgradableProxy proxy) public view returns (address) { | |
// bytes4(keccak256("implementation()")) == 0x5c60da1b | |
(bool success, bytes memory returnData) = address(proxy).staticcall(hex"5c60da1b"); | |
require(success); | |
return abi.decode(returnData, (address)); | |
} | |
function getProxyAdmin(TransparentUpgradableProxy proxy) public view returns (address) { | |
// bytes4(keccak256("admin()")) == 0xf851a440 | |
(bool success, bytes memory returnData) = address(proxy).staticcall(hex"f851a440"); | |
require(success); | |
return abi.decode(returnData, (address)); | |
} | |
function changeProxyAdmin(TransparentUpgradableProxy proxy, address newAdmin) public virtual onlyOwner { | |
proxy.changeAdmin(newAdmin); | |
} | |
function upgrade(TransparentUpgradableProxy proxy, address implementation) public virtual onlyOwner { | |
proxy.upgradeTo(implementation); | |
} | |
} |
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.7.0; | |
contract Test { | |
address proxy; | |
constructor(address _proxy) { | |
proxy = _proxy; | |
} | |
function test() external returns (bytes memory) { | |
bytes memory payload = abi.encodeWithSignature("add(uint256,uint256)", 30, 12); | |
(bool success, bytes memory returnData) = proxy.call(payload); | |
require(success, "call to proxy failed"); | |
return returnData; | |
} | |
} |
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.7.0; | |
import "./UpgradableProxy.sol"; | |
contract TransparentUpgradableProxy is UpgradableProxy { | |
bytes32 constant ADMIN_SLOT = keccak256("leave.me.alone.slot"); | |
event AdminChanged(address previousAdmin, address newAdmin); | |
constructor(address _logic, address admin_) UpgradableProxy(_logic) { | |
_setAdmin(admin_); | |
} | |
modifier isAdmin() { | |
if (msg.sender == _admin()) { | |
_; | |
} else { | |
_fallback(); | |
} | |
} | |
function admin() external isAdmin returns (address admin_) { | |
admin_ = _admin(); | |
} | |
function implementation() external isAdmin returns(address implementation_) { | |
implementation_ = _implementation(); | |
} | |
function upgradeTo(address newImplementation) external isAdmin { | |
_upgradeTo(newImplementation); | |
} | |
function changeAdmin(address newAdmin) external virtual isAdmin { | |
require(newAdmin != address(0), "TransparentUpgradableProxy: new admin is address 0"); | |
emit AdminChanged(_admin(), newAdmin); | |
_setAdmin(newAdmin); | |
} | |
function _setAdmin(address newAdmin) private { | |
bytes32 slot = ADMIN_SLOT; | |
assembly { | |
sstore(slot, newAdmin) | |
} | |
} | |
function _admin() internal view virtual returns(address admin) { | |
bytes32 slot = ADMIN_SLOT; | |
assembly { | |
admin := sload(slot) | |
} | |
} | |
function _beforeFallback() internal virtual override { | |
require(msg.sender != _admin(), "Admin cannot fallback to proxy target"); | |
super._beforeFallback(); | |
} | |
} |
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.7.0; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/utils/Address.sol"; | |
import "./Proxy.sol"; | |
contract UpgradableProxy is Proxy { | |
bytes32 constant IMPLEMENTATION_SLOT = keccak256("proxy.upgradable.pattern.test.mine"); | |
event Upgraded(address indexed implementation); | |
constructor(address _logic) { | |
_setImplementation(_logic); | |
} | |
function getImplementation() public view returns (address) { | |
return _implementation(); | |
} | |
function _implementation() internal view override returns (address) { | |
address impl; | |
bytes32 slot = IMPLEMENTATION_SLOT; | |
assembly { | |
impl := sload(slot) | |
} | |
return impl; | |
} | |
function _upgradeTo(address newImplementation) internal virtual { | |
_setImplementation(newImplementation); | |
emit Upgraded(newImplementation); | |
} | |
function _setImplementation(address newImplementation) private { | |
require(Address.isContract(newImplementation), "address not a contract"); | |
bytes32 slot = IMPLEMENTATION_SLOT; | |
assembly { | |
sstore(slot, newImplementation) | |
} | |
} | |
function _beforeFallback() internal virtual override { | |
super._beforeFallback(); | |
} | |
} |
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.7.0; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/solc-0.7/contracts/math/SafeMath.sol"; | |
contract UpgradedLogic { | |
address proxy; | |
using SafeMath for uint256; | |
event AddedSafely(uint256 result); | |
event Fallback(); | |
function add(uint256 a, uint256 b) external returns (uint256 result) { | |
result = a.add(b); | |
emit AddedSafely(result); | |
} | |
fallback() external { | |
emit Fallback(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment