-
Notifications
You must be signed in to change notification settings - Fork 18
/
Proxy.sol
95 lines (65 loc) · 2.45 KB
/
Proxy.sol
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
pragma solidity ^0.6.0;
// *** IMPORTANT ***
// "onwer" storage variable must be set to a GnosisSafe multisig wallet address:
// - https://github.com/gnosis/safe-contracts/blob/main/contracts/GnosisSafe.sol
contract Proxy {
// ATTENTION: storage variable alignment
address private owner;
address private pendingOwner;
address private implementation;
uint private locked; // 1 = Initialized; 2 = Non upgradable
// --------------------------------------------------------
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
event SetNonUpgradable();
event ImplementationUpdated(address indexed from, address indexed to);
constructor(address _owner, address _implementation) public {
owner = _owner;
implementation = _implementation;
}
fallback () payable external {
_fallback();
}
receive () payable external {
_fallback();
}
function transferOwnership(address _to) external {
require(msg.sender == owner);
pendingOwner = _to;
emit OwnershipTransferRequested(owner, _to);
}
function acceptOwnership() external {
require(msg.sender == pendingOwner);
address oldOwner = owner;
owner = msg.sender;
pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
function setNonUpgradable() public {
require(msg.sender == owner && locked == 1);
locked = 2;
emit SetNonUpgradable();
}
function setImplementation(address _implementation) public {
require(msg.sender == owner && locked != 2);
address oldImplementation = implementation;
implementation = _implementation;
emit ImplementationUpdated(oldImplementation, implementation);
}
function delegate(address _implementation) internal {
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()) }
}
}
function _fallback() internal {
willFallback();
delegate(implementation);
}
function willFallback() internal virtual {
}
}