Skip to content

Commit baa0487

Browse files
committed
solidity: C10lUUPSUpgradeable -> UUPSProposeableUpgradeable
1 parent fa65de7 commit baa0487

2 files changed

Lines changed: 153 additions & 143 deletions

File tree

solidity/contracts/lib/C10lUUPSUpgradeable.sol

Lines changed: 0 additions & 143 deletions
This file was deleted.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
5+
6+
/**
7+
* @title Extended UUPSUpgradeable base contract that prevents simulation
8+
* attacks by the upgrader on confidential Oasis Sapphire contract state.
9+
* @notice This contract adds a proposeUpgrade step before executing the upgrade
10+
* that enforces the upgrade being done in two separate blocks. This prevents
11+
* the simulation attack by the upgrader without user's knowledge.
12+
*
13+
* #### Example
14+
*
15+
* ```solidity
16+
* contract MyContract is UUPSProposeableUpgradeable, OwnableUpgradeable {
17+
* function initialize(address _owner) public initializer {
18+
* __Ownable_init(_owner);
19+
* }
20+
*
21+
* // Gate proposeUpgrade with appropriate modifier.
22+
* function _authorizeProposeUpgrade() internal onlyOwner { }
23+
*
24+
* // Gate UUPSUpgradeable.authorizeUpgrade with appropriate modifier.
25+
* function _authorizeUpgrade(address newImpl) internal onlyOwner onlyProposeUpgrade(newImpl) { }
26+
* }
27+
* ```
28+
*/
29+
abstract contract UUPSProposeableUpgradeable is UUPSUpgradeable {
30+
/// @custom:storage-location erc7201:oasisprotocol.storage.UUPSProposeableUpgradeable
31+
struct UUPSProposeableUpgradeableStorage {
32+
address _newImplementation;
33+
uint256 _minBlockNumber;
34+
}
35+
36+
// keccak256(abi.encode(uint256(keccak256("oasisprotocol.storage.UUPSProposeableUpgradeable")) - 1)) & ~bytes32(uint256(0xff))
37+
bytes32 private constant UUPSProposeableUpgradeableStorageLocation =
38+
0xa97571fb9a74c4c520fcdddf68345a7b192979c0085272968c2570875f6f0000;
39+
40+
function _getUUPSProposeableUpgradeableStorage()
41+
private
42+
pure
43+
returns (UUPSProposeableUpgradeableStorage storage $)
44+
{
45+
assembly {
46+
$.slot := UUPSProposeableUpgradeableStorageLocation
47+
}
48+
}
49+
50+
error ImplementationDoesNotMatch();
51+
error MinBlockNumberNotReached();
52+
error MinBlockNumberInPast();
53+
54+
event UpgradeProposed(
55+
address indexed newImplementation,
56+
uint256 indexed minBlockNumber
57+
);
58+
59+
event UpgradeAccepted(
60+
address indexed newImplementation,
61+
uint256 indexed minBlockNumber
62+
);
63+
64+
/**
65+
* @notice Initializes the contract.
66+
*/
67+
function __UUPSProposeableUpgradeable_init()
68+
internal
69+
onlyInitializing
70+
{
71+
}
72+
73+
/**
74+
* @notice Reverts unless the transaction is signed by an authorized
75+
* instance of the configured ROFL app.
76+
*/
77+
modifier acceptProposedUpgrade(address newImpl) {
78+
_acceptProposeUpgrade(newImpl);
79+
80+
_;
81+
}
82+
83+
/**
84+
* @notice Function that should revert when `msg.sender` is not authorized
85+
* to propose the upgrade. Use {proposedUpgradeImplementation} and
86+
* {proposeedMinBlockNumber} to fetch proposal details. Called by
87+
* {proposeUpgrade}.
88+
*
89+
* Normally, this function will use an xref:access.adoc[access control]
90+
* modifier such as {Ownable-onlyOwner}.
91+
*
92+
* ```solidity
93+
* function _authorizeUpgradeProposal() internal onlyOwner {}
94+
* ```
95+
*/
96+
function _authorizeProposeUpgrade() internal virtual;
97+
98+
/**
99+
* @notice Returns the new implementation address of the proposed upgrade.
100+
*/
101+
function proposedUpgradeImplementation() public view virtual returns (address) {
102+
UUPSProposeableUpgradeableStorage storage $ = _getUUPSProposeableUpgradeableStorage();
103+
return $._newImplementation;
104+
}
105+
106+
/**
107+
* @notice Returns the proposed upgrade minimum block number.
108+
*/
109+
function proposedUpgradeMinBlockNumber() public view virtual returns (uint256) {
110+
UUPSProposeableUpgradeableStorage storage $ = _getUUPSProposeableUpgradeableStorage();
111+
return $._minBlockNumber;
112+
}
113+
114+
/**
115+
* @notice Reverts unless the implementation matches and the current block
116+
* number is at least one block ahead of the minBlockNumber.
117+
*/
118+
function _acceptProposeUpgrade(address newImplementation) internal view virtual {
119+
if (newImplementation != proposedUpgradeImplementation()) {
120+
revert ImplementationDoesNotMatch();
121+
}
122+
if (block.number <= proposedUpgradeMinBlockNumber()) {
123+
revert MinBlockNumberNotReached();
124+
}
125+
emit UpgradeAccepted(newImplementation, proposedUpgradeMinBlockNumber());
126+
127+
UUPSProposeableUpgradeableStorage storage $ = _getUUPSProposeableUpgradeableStorage();
128+
$._newImplementation = address(0);
129+
$._minBlockNumber = 0;
130+
}
131+
132+
/**
133+
* @notice Propose the upgrade to the new implementation address after the
134+
* given block number. If minBlockNumber is zero, take the current block
135+
* number.
136+
*/
137+
function proposeUpgrade(address newImplementation, uint256 minBlockNumber) public virtual {
138+
if (minBlockNumber == 0) {
139+
minBlockNumber = block.number;
140+
}
141+
if (minBlockNumber < block.number) {
142+
revert MinBlockNumberInPast();
143+
}
144+
145+
UUPSProposeableUpgradeableStorage storage $ = _getUUPSProposeableUpgradeableStorage();
146+
$._newImplementation = newImplementation;
147+
$._minBlockNumber = minBlockNumber;
148+
149+
_authorizeProposeUpgrade();
150+
151+
emit UpgradeProposed(newImplementation, minBlockNumber);
152+
}
153+
}

0 commit comments

Comments
 (0)