1- pragma solidity 0.7.6 ;
2-
31// SPDX-License-Identifier: GPL-3.0-only
2+ pragma solidity 0.8.30 ;
43
5- import "../../RocketBase.sol " ;
6- import "../../../interface/dao/node/RocketDAONodeTrustedUpgradeInterface.sol " ;
7- import "../../../interface/util/IERC20.sol " ;
8-
9- // Handles network contract upgrades
4+ import {RocketStorageInterface} from "../../../interface/RocketStorageInterface.sol " ;
5+ import {RocketDAONodeTrustedUpgradeInterface} from "../../../interface/dao/node/RocketDAONodeTrustedUpgradeInterface.sol " ;
6+ import {RocketDAOProtocolSettingsSecurityInterface} from "../../../interface/dao/protocol/settings/RocketDAOProtocolSettingsSecurityInterface.sol " ;
7+ import {RocketBase} from "../../RocketBase.sol " ;
108
9+ /// @notice Handles network contract upgrades
1110contract RocketDAONodeTrustedUpgrade is RocketBase , RocketDAONodeTrustedUpgradeInterface {
12-
1311 // Events
12+ event UpgradePending (uint256 upgradeProposalID , bytes32 indexed upgradeType , bytes32 indexed name , uint256 time );
13+ event UpgradeVetoed (uint256 upgradeProposalID , uint256 time );
1414 event ContractUpgraded (bytes32 indexed name , address indexed oldAddress , address indexed newAddress , uint256 time );
1515 event ContractAdded (bytes32 indexed name , address indexed newAddress , uint256 time );
1616 event ABIUpgraded (bytes32 indexed name , uint256 time );
1717 event ABIAdded (bytes32 indexed name , uint256 time );
1818
19+ // The namespace for any storage data used by this contract
20+ string constant private daoUpgradeNameSpace = "dao.upgrade. " ;
21+
22+ // Immutables
23+ bytes32 immutable internal daoTrustedBootstrapKey;
24+ bytes32 immutable internal typeUpgradeContract;
25+ bytes32 immutable internal typeAddContract;
26+ bytes32 immutable internal typeUpgradeABI;
27+ bytes32 immutable internal typeAddABI;
28+
29+ // Only allow bootstrapping when enabled
30+ modifier onlyBootstrapMode () {
31+ require (getBool (daoTrustedBootstrapKey) == false , "Bootstrap mode not engaged " );
32+ _;
33+ }
34+
1935 // Construct
2036 constructor (RocketStorageInterface _rocketStorageAddress ) RocketBase (_rocketStorageAddress) {
21- version = 1 ;
37+ version = 2 ;
38+
39+ // Precompute keys
40+ typeUpgradeContract = keccak256 (abi.encodePacked ("upgradeContract " ));
41+ typeAddContract = keccak256 (abi.encodePacked ("addContract " ));
42+ typeUpgradeABI = keccak256 (abi.encodePacked ("upgradeABI " ));
43+ typeAddABI = keccak256 (abi.encodePacked ("addABI " ));
44+ daoTrustedBootstrapKey = keccak256 (abi.encodePacked ("dao.trustednodes. " , "bootstrapmode.disabled " ));
2245 }
2346
24- // Main accessor for performing an upgrade, be it a contract or abi for a contract
25- // Will require > 50% of trusted DAO members to run when bootstrap mode is disabled
47+ /// @notice Called when an upgrade proposal is executed, creates an upgrade proposal that can be vetoed by the
48+ /// security council or executed after the upgrade delay period has passed
49+ /// @param _type Type of upgrade (valid values: "upgradeContract", "addContract", "upgradeABI", "addABI")
50+ /// @param _name Contract name to upgrade
51+ /// @param _contractAbi ABI of the upgraded contract
52+ /// @param _contractAddress Address of the upgraded contract
2653 function upgrade (string memory _type , string memory _name , string memory _contractAbi , address _contractAddress ) override external onlyLatestContract ("rocketDAONodeTrustedProposals " , msg .sender ) {
27- // What action are we performing?
54+ uint256 upgradeProposalID = getTotal () + 1 ;
55+ // Compute when the proposal can be executed if not vetoed by the security council
56+ uint256 startTime = block .timestamp ;
57+ RocketDAOProtocolSettingsSecurityInterface rocketDAOProtocolSettingsSecurity = RocketDAOProtocolSettingsSecurityInterface (getContractAddress ("rocketDAOProtocolSettingsSecurity " ));
58+ uint256 endTime = startTime + rocketDAOProtocolSettingsSecurity.getUpgradeDelay ();
59+ // Store data
2860 bytes32 typeHash = keccak256 (abi.encodePacked (_type));
29- // Lets do it!
30- if (typeHash == keccak256 (abi.encodePacked ("upgradeContract " ))) _upgradeContract (_name, _contractAddress, _contractAbi);
31- if (typeHash == keccak256 (abi.encodePacked ("addContract " ))) _addContract (_name, _contractAddress, _contractAbi);
32- if (typeHash == keccak256 (abi.encodePacked ("upgradeABI " ))) _upgradeABI (_name, _contractAbi);
33- if (typeHash == keccak256 (abi.encodePacked ("addABI " ))) _addABI (_name, _contractAbi);
61+ setBytes32 (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "type " , upgradeProposalID)), typeHash);
62+ setString (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "name " , upgradeProposalID)), _name);
63+ setString (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "abi " , upgradeProposalID)), _contractAbi);
64+ setAddress (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "address " , upgradeProposalID)), _contractAddress);
65+ setUint (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "end " , upgradeProposalID)), endTime);
66+ addUint (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "total " )), 1 );
67+ // Emit event
68+ emit UpgradePending (upgradeProposalID, typeHash, keccak256 (abi.encodePacked (_name)), block .timestamp );
3469 }
3570
71+ /// @notice Called by the proposal contract when a veto passes
72+ /// @param _upgradeProposalID ID of the upgrade proposal to veto
73+ function veto (uint256 _upgradeProposalID ) override external onlyLatestContract ("rocketDAOSecurityUpgrade " , msg .sender ) {
74+ // Validate proposal state
75+ require (getState (_upgradeProposalID) == UpgradeProposalState.Pending, "Proposal has already succeeded, expired, or executed " );
76+ // Mark the upgrade as vetoed
77+ setBool (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "vetoed " , _upgradeProposalID)), true );
78+ // Emit event
79+ emit UpgradeVetoed (_upgradeProposalID, block .timestamp );
80+ }
81+
82+ /// @notice Called after upgrade delay has passed to perform the upgrade
83+ /// @param _upgradeProposalID ID of the upgrade proposal to execute
84+ /// @dev Must be called by a registered trusted node
85+ function execute (uint256 _upgradeProposalID ) override external onlyTrustedNode (msg .sender ) {
86+ // Validate proposal state
87+ require (getState (_upgradeProposalID) == UpgradeProposalState.Succeeded, "Proposal has not succeeded or has been vetoed or executed " );
88+ // Mark as executed
89+ setBool (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "executed " , _upgradeProposalID)), true );
90+ // Execute the upgrade
91+ _execute (getType (_upgradeProposalID), getName (_upgradeProposalID), getUpgradeABI (_upgradeProposalID), getUpgradeAddress (_upgradeProposalID));
92+ }
93+
94+ /// @notice Immediately execute an upgrade if bootstrap mode is still enabled
95+ /// @param _type Type of upgrade (valid values: "upgradeContract", "addContract", "upgradeABI", "addABI")
96+ /// @param _name Contract name to upgrade
97+ /// @param _contractAbi ABI of the upgraded contract
98+ /// @param _contractAddress Address of the upgraded contract
99+ function bootstrapUpgrade (string memory _type , string memory _name , string memory _contractAbi , address _contractAddress ) override external onlyGuardian onlyBootstrapMode {
100+ bytes32 typeHash = keccak256 (abi.encodePacked (_type));
101+ _execute (typeHash, _name, _contractAbi, _contractAddress);
102+ }
36103
37- /*** Internal Upgrade Methods for the Trusted Node DAO ****************/
104+ /// @dev Internal implementation of the execution process
105+ function _execute (bytes32 _typeHash , string memory _name , string memory _contractAbi , address _contractAddress ) internal {
106+ if (_typeHash == typeUpgradeContract) _upgradeContract (_name, _contractAddress, _contractAbi);
107+ else if (_typeHash == typeAddContract) _addContract (_name, _contractAddress, _contractAbi);
108+ else if (_typeHash == typeUpgradeABI) _upgradeABI (_name, _contractAbi);
109+ else if (_typeHash == typeAddABI) _addABI (_name, _contractAbi);
110+ else revert ("Invalid upgrade type " );
111+ }
38112
39- // Upgrade a network contract
113+ /// @dev Performs an update to a contract and ABI simultaneously
40114 function _upgradeContract (string memory _name , address _contractAddress , string memory _contractAbi ) internal {
41115 // Check contract being upgraded
42116 bytes32 nameHash = keccak256 (abi.encodePacked (_name));
43- require (nameHash != keccak256 (abi.encodePacked ("rocketVault " )), "Cannot upgrade the vault " );
44- require (nameHash != keccak256 (abi.encodePacked ("rocketTokenRETH " )), "Cannot upgrade token contracts " );
45- require (nameHash != keccak256 (abi.encodePacked ("rocketTokenRPL " )), "Cannot upgrade token contracts " );
117+ require (nameHash != keccak256 (abi.encodePacked ("rocketVault " )), "Cannot upgrade the vault " );
118+ require (nameHash != keccak256 (abi.encodePacked ("rocketTokenRETH " )), "Cannot upgrade token contracts " );
119+ require (nameHash != keccak256 (abi.encodePacked ("rocketTokenRPL " )), "Cannot upgrade token contracts " );
46120 require (nameHash != keccak256 (abi.encodePacked ("rocketTokenRPLFixedSupply " )), "Cannot upgrade token contracts " );
47- require (nameHash != keccak256 (abi.encodePacked ("casperDeposit " )), "Cannot upgrade the casper deposit contract " );
48- require (nameHash != keccak256 (abi.encodePacked ("rocketMinipoolPenalty " )), "Cannot upgrade minipool penalty contract " );
121+ require (nameHash != keccak256 (abi.encodePacked ("casperDeposit " )), "Cannot upgrade the casper deposit contract " );
122+ require (nameHash != keccak256 (abi.encodePacked ("rocketMinipoolPenalty " )), "Cannot upgrade minipool penalty contract " );
49123 // Get old contract address & check contract exists
50124 address oldContractAddress = getAddress (keccak256 (abi.encodePacked ("contract.address " , _name)));
51125 require (oldContractAddress != address (0x0 ), "Contract does not exist " );
@@ -67,7 +141,7 @@ contract RocketDAONodeTrustedUpgrade is RocketBase, RocketDAONodeTrustedUpgradeI
67141 emit ContractUpgraded (nameHash, oldContractAddress, _contractAddress, block .timestamp );
68142 }
69143
70- // Add a new network contract
144+ /// @dev Adds a new contract to the protocol
71145 function _addContract (string memory _name , address _contractAddress , string memory _contractAbi ) internal {
72146 // Check contract name
73147 bytes32 nameHash = keccak256 (abi.encodePacked (_name));
@@ -91,7 +165,7 @@ contract RocketDAONodeTrustedUpgrade is RocketBase, RocketDAONodeTrustedUpgradeI
91165 emit ContractAdded (nameHash, _contractAddress, block .timestamp );
92166 }
93167
94- // Upgrade a network contract ABI
168+ /// @dev Upgrades an existing ABI
95169 function _upgradeABI (string memory _name , string memory _contractAbi ) internal {
96170 // Check ABI exists
97171 string memory existingAbi = getString (keccak256 (abi.encodePacked ("contract.abi " , _name)));
@@ -105,7 +179,7 @@ contract RocketDAONodeTrustedUpgrade is RocketBase, RocketDAONodeTrustedUpgradeI
105179 emit ABIUpgraded (keccak256 (abi.encodePacked (_name)), block .timestamp );
106180 }
107181
108- // Add a new network contract ABI
182+ /// @dev Adds a new ABI to the protocol
109183 function _addABI (string memory _name , string memory _contractAbi ) internal {
110184 // Check ABI name
111185 bytes32 nameHash = keccak256 (abi.encodePacked (_name));
@@ -123,4 +197,66 @@ contract RocketDAONodeTrustedUpgrade is RocketBase, RocketDAONodeTrustedUpgradeI
123197 emit ABIAdded (nameHash, block .timestamp );
124198 }
125199
200+ /// @notice Get the total number of upgrade proposals
201+ function getTotal () override public view returns (uint256 ) {
202+ return getUint (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "total " )));
203+ }
204+
205+ /// @notice Return the state of the specified upgrade proposal
206+ /// @param _upgradeProposalID ID of the upgrade proposal to query
207+ function getState (uint256 _upgradeProposalID ) override public view returns (UpgradeProposalState) {
208+ // Check the proposal ID is legit
209+ require (getTotal () >= _upgradeProposalID && _upgradeProposalID > 0 , "Invalid upgrade proposal ID " );
210+ if (getVetoed (_upgradeProposalID)) {
211+ return UpgradeProposalState.Vetoed;
212+ } else if (getExecuted (_upgradeProposalID)) {
213+ return UpgradeProposalState.Executed;
214+ } else if (block .timestamp < getEnd (_upgradeProposalID)) {
215+ return UpgradeProposalState.Pending;
216+ } else {
217+ return UpgradeProposalState.Succeeded;
218+ }
219+ }
220+
221+ /// @notice Get the end time of this proposal (when the upgrade delay ends)
222+ /// @param _upgradeProposalID ID of the upgrade proposal to query
223+ function getEnd (uint256 _upgradeProposalID ) override public view returns (uint256 ) {
224+ return getUint (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "end " , _upgradeProposalID)));
225+ }
226+
227+ /// @notice Get whether the proposal has been executed
228+ /// @param _upgradeProposalID ID of the upgrade proposal to query
229+ function getExecuted (uint256 _upgradeProposalID ) override public view returns (bool ) {
230+ return getBool (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "executed " , _upgradeProposalID)));
231+ }
232+
233+ /// @notice Get whether the proposal has been vetoed
234+ /// @param _upgradeProposalID ID of the upgrade proposal to query
235+ function getVetoed (uint256 _upgradeProposalID ) override public view returns (bool ) {
236+ return getBool (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "vetoed " , _upgradeProposalID)));
237+ }
238+
239+ /// @notice Get the proposal type
240+ /// @param _upgradeProposalID ID of the upgrade proposal to query
241+ function getType (uint256 _upgradeProposalID ) override public view returns (bytes32 ) {
242+ return getBytes32 (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "type " , _upgradeProposalID)));
243+ }
244+
245+ /// @notice Get the proposed upgrade contract name
246+ /// @param _upgradeProposalID ID of the upgrade proposal to query
247+ function getName (uint256 _upgradeProposalID ) override public view returns (string memory ) {
248+ return getString (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "name " , _upgradeProposalID)));
249+ }
250+
251+ /// @notice Get the proposed upgrade contract address
252+ /// @param _upgradeProposalID ID of the upgrade proposal to query
253+ function getUpgradeAddress (uint256 _upgradeProposalID ) override public view returns (address ) {
254+ return getAddress (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "address " , _upgradeProposalID)));
255+ }
256+
257+ /// @notice Get the proposed upgrade contract ABI
258+ /// @param _upgradeProposalID ID of the upgrade proposal to query
259+ function getUpgradeABI (uint256 _upgradeProposalID ) override public view returns (string memory ) {
260+ return getString (keccak256 (abi.encodePacked (daoUpgradeNameSpace, "abi " , _upgradeProposalID)));
261+ }
126262}
0 commit comments