/
UUPSImplementation.sol
79 lines (61 loc) · 2.45 KB
/
UUPSImplementation.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
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
import "../interfaces/IUUPSImplementation.sol";
import "../errors/AddressError.sol";
import "../errors/ChangeError.sol";
import "../utils/AddressUtil.sol";
import "./ProxyStorage.sol";
abstract contract UUPSImplementation is IUUPSImplementation, ProxyStorage {
/**
* @inheritdoc IUUPSImplementation
*/
function simulateUpgradeTo(address newImplementation) public override {
ProxyStore storage store = _proxyStore();
store.simulatingUpgrade = true;
address currentImplementation = store.implementation;
store.implementation = newImplementation;
(bool rollbackSuccessful, ) = newImplementation.delegatecall(
abi.encodeCall(this.upgradeTo, (currentImplementation))
);
if (!rollbackSuccessful || _proxyStore().implementation != currentImplementation) {
revert UpgradeSimulationFailed();
}
store.simulatingUpgrade = false;
// solhint-disable-next-line reason-string
revert();
}
/**
* @inheritdoc IUUPSImplementation
*/
function getImplementation() external view override returns (address) {
return _proxyStore().implementation;
}
function _upgradeTo(address newImplementation) internal virtual {
if (newImplementation == address(0)) {
revert AddressError.ZeroAddress();
}
if (!AddressUtil.isContract(newImplementation)) {
revert AddressError.NotAContract(newImplementation);
}
ProxyStore storage store = _proxyStore();
if (newImplementation == store.implementation) {
revert ChangeError.NoChange();
}
if (!store.simulatingUpgrade && _implementationIsSterile(newImplementation)) {
revert ImplementationIsSterile(newImplementation);
}
store.implementation = newImplementation;
emit Upgraded(address(this), newImplementation);
}
function _implementationIsSterile(
address candidateImplementation
) internal virtual returns (bool) {
(bool simulationReverted, bytes memory simulationResponse) = address(this).delegatecall(
abi.encodeCall(this.simulateUpgradeTo, (candidateImplementation))
);
return
!simulationReverted &&
keccak256(abi.encodePacked(simulationResponse)) ==
keccak256(abi.encodePacked(UpgradeSimulationFailed.selector));
}
}