-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathProxy.sol
More file actions
121 lines (100 loc) · 3.19 KB
/
Proxy.sol
File metadata and controls
121 lines (100 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;
library AddressUtils {
function isContract(address addr) internal view returns (bool) {
uint256 size;
// solium-disable-next-line security/no-inline-assembly
assembly { size := extcodesize(addr) }
return size > 0;
}
}
contract Proxy {
using AddressUtils for address;
bytes32 private constant ADMIN_SLOT = 0xde50c0ef4724e938441b7d87888451dee5481c5f4cdb090e8051ee74ce71c31c;
bytes32 private constant IMPLEMENTATION_SLOT = 0x454e447e72dbaa44ab6e98057df04d15461fc11a64ce58e5e1472346dea4223f;
constructor (address _i) {
require(_i.isContract());
_setImplementation(_i);
_setAdmin(msg.sender);
}
event AdminChanged (address admin);
event Upgraded (address implementation);
modifier onlyAdmin () {
require(msg.sender == _admin());
_;
}
/// @dev 更换Proxy合约的管理者
/// @param _newAdmin 新的管理者地址
function proxyChangeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0));
_setAdmin(_newAdmin);
emit AdminChanged(_newAdmin);
}
/// @dev 升级使用的Bounty合约
/// @param _newImplementation 新的合约地址
function proxyUpgradeTo(address _newImplementation) public onlyAdmin {
require(_newImplementation.isContract());
_setImplementation(_newImplementation);
emit Upgraded(_newImplementation);
}
/// @dev 升级使用的Bounty合约并且直接执行调用
/// @param _newImplementation 新的合约地址
/// @param _data 需要在新合约上调用的方法编码
function proxyUpgradeToAndCall(
address _newImplementation,
bytes calldata _data
) external payable onlyAdmin returns (bytes memory) {
proxyUpgradeTo(_newImplementation);
(bool success, bytes memory data) = address(this).call{value:msg.value}(_data);
require(success);
return data;
}
function _admin () internal view returns (address a) {
bytes32 slot = ADMIN_SLOT;
assembly {
a := sload(slot)
}
}
function _implementation () internal view returns (address i) {
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
i := sload(slot)
}
}
function admin() external view onlyAdmin returns (address) {
return _admin();
}
function implementation() external view onlyAdmin returns (address) {
return _implementation();
}
function _setAdmin (address newAdmin) internal {
bytes32 slot = ADMIN_SLOT;
assembly {
sstore(slot, newAdmin)
}
}
function _setImplementation (address newImplementation) internal {
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
sstore(slot, newImplementation)
}
}
/// @dev fallback函数,除了proxyChangeAdmin和proxyUpgradeTo方法以外的所有
/// 对合约的调用均会最终会被执行该方法。函数会将所有调用的data直接转发至Bounty合
/// 约,并返回对应的结果。
fallback () external payable {
address i = _implementation();
// solium-disable-next-line security/no-inline-assembly
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), i, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
receive () external payable {
revert();
}
}