Skip to content

Commit d141a5b

Browse files
committed
Implement RPIP-45 allowlisted controllers
1 parent 574e69f commit d141a5b

11 files changed

+263
-42
lines changed

contracts/contract/dao/protocol/RocketDAOProtocol.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ contract RocketDAOProtocol is RocketBase, RocketDAOProtocolInterface {
1515
event BootstrapSettingUint(string settingContractName, string settingPath, uint256 value, uint256 time);
1616
event BootstrapSettingBool(string settingContractName, string settingPath, bool value, uint256 time);
1717
event BootstrapSettingAddress(string settingContractName, string settingPath, address value, uint256 time);
18+
event BootstrapSettingAddressList(string settingContractName, string settingPath, address[] value, uint256 time);
1819
event BootstrapSettingClaimers(uint256 trustedNodePercent, uint256 protocolPercent, uint256 nodePercent, uint256 time);
1920
event BootstrapSpendTreasury(string invoiceID, address recipientAddress, uint256 amount, uint256 time);
2021
event BootstrapTreasuryNewContract(string contractName, address recipientAddress, uint256 amountPerPeriod, uint256 periodLength, uint256 startTime, uint256 numPeriods, uint256 time);
@@ -76,6 +77,12 @@ contract RocketDAOProtocol is RocketBase, RocketDAOProtocolInterface {
7677
emit BootstrapSettingAddress(_settingContractName, _settingPath, _value, block.timestamp);
7778
}
7879

80+
/// @notice Bootstrap mode - Address list Setting
81+
function bootstrapSettingAddressList(string memory _settingContractName, string memory _settingPath, address[] calldata _value) override external onlyGuardian onlyBootstrapMode onlyLatestContract("rocketDAOProtocol", address(this)) {
82+
RocketDAOProtocolProposalsInterface(getContractAddress("rocketDAOProtocolProposals")).proposalSettingAddressList(_settingContractName, _settingPath, _value);
83+
emit BootstrapSettingAddressList(_settingContractName, _settingPath, _value, block.timestamp);
84+
}
85+
7986
/// @notice Bootstrap mode - Set a claiming contract to receive a % of RPL inflation rewards
8087
function bootstrapSettingClaimers(uint256 _trustedNodePercent, uint256 _protocolPercent, uint256 _nodePercent) override external onlyGuardian onlyBootstrapMode onlyLatestContract("rocketDAOProtocol", address(this)) {
8188
RocketDAOProtocolProposalsInterface(getContractAddress("rocketDAOProtocolProposals")).proposalSettingRewardsClaimers(_trustedNodePercent, _protocolPercent, _nodePercent);

contracts/contract/dao/protocol/RocketDAOProtocolProposals.sol

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ contract RocketDAOProtocolProposals is RocketBase, RocketDAOProtocolProposalsInt
2323
event ProposalSettingUint(string settingContractName, string settingPath, uint256 value, uint256 time);
2424
event ProposalSettingBool(string settingContractName, string settingPath, bool value, uint256 time);
2525
event ProposalSettingAddress(string settingContractName, string settingPath, address value, uint256 time);
26+
event ProposalSettingAddressList(string settingContractName, string settingPath, address[] value, uint256 time);
2627
event ProposalSettingRewardsClaimers(uint256 trustedNodePercent, uint256 protocolPercent, uint256 nodePercent, uint256 time);
2728
event ProposalSecurityInvite(string id, address memberAddress, uint256 time);
2829
event ProposalSecurityKick(address memberAddress, uint256 time);
@@ -97,6 +98,16 @@ contract RocketDAOProtocolProposals is RocketBase, RocketDAOProtocolProposalsInt
9798
emit ProposalSettingAddress(_settingContractName, _settingPath, _value, block.timestamp);
9899
}
99100

101+
/// @notice Change one of the current address[] settings of the protocol DAO
102+
/// @param _settingContractName Contract name of the setting to change
103+
/// @param _settingPath Setting path to change
104+
/// @param _value[] New setting value
105+
function proposalSettingAddressList(string memory _settingContractName, string memory _settingPath, address[] calldata _value) override public onlyExecutingContracts() {
106+
RocketDAOProtocolSettingsInterface rocketDAOProtocolSettings = RocketDAOProtocolSettingsInterface(getContractAddress(_settingContractName));
107+
rocketDAOProtocolSettings.setSettingAddressList(_settingPath, _value);
108+
emit ProposalSettingAddressList(_settingContractName, _settingPath, _value, block.timestamp);
109+
}
110+
100111
/// @notice Updates the percentages the trusted nodes use when calculating RPL reward trees. Percentages must add up to 100%
101112
/// @param _trustedNodePercent The percentage of rewards paid to the trusted node set (as a fraction of 1e18)
102113
/// @param _protocolPercent The percentage of rewards paid to the protocol dao (as a fraction of 1e18)
Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,88 @@
11
// SPDX-License-Identifier: GPL-3.0-only
22
pragma solidity >0.5.0 <0.9.0;
33

4-
import "../../../RocketBase.sol";
5-
import "../../../../interface/dao/protocol/settings/RocketDAOProtocolSettingsInterface.sol";
4+
import {RocketStorageInterface} from "../../../../interface/RocketStorageInterface.sol";
5+
import {RocketDAOProtocolSettingsInterface} from "../../../../interface/dao/protocol/settings/RocketDAOProtocolSettingsInterface.sol";
6+
import {RocketBase} from "../../../RocketBase.sol";
67

78
// Settings in RP which the DAO will have full control over
89
// This settings contract enables storage using setting paths with namespaces, rather than explicit set methods
910
abstract contract RocketDAOProtocolSettings is RocketBase, RocketDAOProtocolSettingsInterface {
1011

11-
1212
// The namespace for a particular group of settings
1313
bytes32 settingNameSpace;
1414

15-
1615
// Only allow updating from the DAO proposals contract
1716
modifier onlyDAOProtocolProposal() {
1817
// If this contract has been initialised, only allow access from the proposals contract
19-
if(getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) require(getContractAddress("rocketDAOProtocolProposals") == msg.sender, "Only DAO Protocol Proposals contract can update a setting");
18+
if (getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) require(getContractAddress("rocketDAOProtocolProposals") == msg.sender, "Only DAO Protocol Proposals contract can update a setting");
2019
_;
2120
}
2221

23-
2422
// Construct
2523
constructor(RocketStorageInterface _rocketStorageAddress, string memory _settingNameSpace) RocketBase(_rocketStorageAddress) {
2624
// Apply the setting namespace
2725
settingNameSpace = keccak256(abi.encodePacked("dao.protocol.setting.", _settingNameSpace));
2826
}
2927

30-
3128
/*** Uints ****************/
3229

3330
// A general method to return any setting given the setting path is correct, only accepts uints
3431
function getSettingUint(string memory _settingPath) public view override returns (uint256) {
3532
return getUint(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
36-
}
33+
}
3734

3835
// Update a Uint setting, can only be executed by the DAO contract when a majority on a setting proposal has passed and been executed
3936
function setSettingUint(string memory _settingPath, uint256 _value) virtual public override onlyDAOProtocolProposal {
4037
// Update setting now
4138
setUint(keccak256(abi.encodePacked(settingNameSpace, _settingPath)), _value);
42-
}
43-
39+
}
4440

4541
/*** Bools ****************/
4642

4743
// A general method to return any setting given the setting path is correct, only accepts bools
4844
function getSettingBool(string memory _settingPath) public view override returns (bool) {
4945
return getBool(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
50-
}
46+
}
5147

5248
// Update a setting, can only be executed by the DAO contract when a majority on a setting proposal has passed and been executed
5349
function setSettingBool(string memory _settingPath, bool _value) virtual public override onlyDAOProtocolProposal {
5450
// Update setting now
5551
setBool(keccak256(abi.encodePacked(settingNameSpace, _settingPath)), _value);
5652
}
5753

58-
5954
/*** Addresses ****************/
6055

6156
// A general method to return any setting given the setting path is correct, only accepts addresses
6257
function getSettingAddress(string memory _settingPath) external view override returns (address) {
6358
return getAddress(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
64-
}
59+
}
6560

6661
// Update a setting, can only be executed by the DAO contract when a majority on a setting proposal has passed and been executed
6762
function setSettingAddress(string memory _settingPath, address _value) virtual external override onlyDAOProtocolProposal {
6863
// Update setting now
6964
setAddress(keccak256(abi.encodePacked(settingNameSpace, _settingPath)), _value);
7065
}
7166

67+
/*** Address lists ****************/
68+
69+
// A general method to return any setting given the setting path is correct, only accepts address lists
70+
function getSettingAddressList(string memory _settingPath) public view override returns (address[] memory) {
71+
uint256 key = uint256(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
72+
uint256 count = getUint(bytes32(key));
73+
address[] memory addressList = new address[](count);
74+
for (uint256 i = 0; i < count; ++i) {
75+
addressList[i] = getAddress(bytes32(key + i));
76+
}
77+
return addressList;
78+
}
79+
80+
// Update a setting, can only be executed by the DAO contract when a majority on a setting proposal has passed and been executed
81+
function setSettingAddressList(string memory _settingPath, address[] calldata _value) virtual public override onlyDAOProtocolProposal {
82+
uint256 key = uint256(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
83+
setUint(bytes32(key), _value.length);
84+
for (uint256 i = 0; i < _value.length; ++i) {
85+
setAddress(bytes32(key + i), _value[i]);
86+
}
87+
}
7288
}

contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsNetwork.sol

Lines changed: 81 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import {RocketDAOProtocolSettings} from "./RocketDAOProtocolSettings.sol";
1010
/// @notice Network auction settings
1111
contract RocketDAOProtocolSettingsNetwork is RocketDAOProtocolSettings, RocketDAOProtocolSettingsNetworkInterface {
1212

13+
modifier onlyAllowListedController() {
14+
require(isAllowListedController(msg.sender), "Not on allow list");
15+
_;
16+
}
17+
1318
constructor(RocketStorageInterface _rocketStorageAddress) RocketDAOProtocolSettings(_rocketStorageAddress, "network") {
1419
version = 4;
1520
// Initialise settings on deployment
@@ -42,8 +47,6 @@ contract RocketDAOProtocolSettingsNetwork is RocketDAOProtocolSettings, RocketDA
4247
if (getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) {
4348
// Some safety guards for certain settings
4449
bytes32 settingKey = keccak256(bytes(_settingPath));
45-
bool voterShareModified = false;
46-
bool nodeShareModified = false;
4750
if (settingKey == keccak256(bytes("network.consensus.threshold"))) {
4851
require(_value >= 0.51 ether, "Consensus threshold must be 51% or higher");
4952
} else if (settingKey == keccak256(bytes("network.node.fee.minimum"))) {
@@ -55,32 +58,14 @@ contract RocketDAOProtocolSettingsNetwork is RocketDAOProtocolSettings, RocketDA
5558
} else if (settingKey == keccak256(bytes("network.submit.balances.frequency"))) {
5659
require(_value >= 1 hours, "The submit frequency must be >= 1 hour");
5760
} else if (settingKey == keccak256(bytes("network.node.commission.share.security.council.adder"))) {
58-
uint256 maxAdderValue = getSettingUint("network.max.node.commission.share.council.adder");
59-
require(_value <= maxAdderValue, "Value must be <= max value");
60-
uint256 maxVoterValue = getSettingUint("network.voter.share");
61-
require(_value <= maxVoterValue, "Value must be <= voter share");
62-
voterShareModified = true;
63-
nodeShareModified = true;
61+
return _setNodeShareSecurityCouncilAdder(_value);
6462
} else if (settingKey == keccak256(bytes("network.node.commission.share"))) {
65-
nodeShareModified = true;
63+
return _setNodeCommissionShare(_value);
6664
} else if (settingKey == keccak256(bytes("network.voter.share"))) {
67-
voterShareModified = true;
65+
return _setVoterShare(_value);
6866
}
6967
// Update setting now
7068
_setSettingUint(_settingPath, _value);
71-
// Check for changes to UARS parameters
72-
if (voterShareModified || nodeShareModified) {
73-
// Check rETH commission invariant
74-
require(getRethCommission() <= 1 ether, "rETH Commission must be <= 100%");
75-
// If one of the UARS parameters changed, notify RocketNetworkRevenues
76-
RocketNetworkRevenuesInterface rocketNetworkRevenues = RocketNetworkRevenuesInterface(getContractAddress("rocketNetworkRevenues"));
77-
if (voterShareModified) {
78-
rocketNetworkRevenues.setVoterShare(getEffectiveVoterShare());
79-
}
80-
if (nodeShareModified) {
81-
rocketNetworkRevenues.setNodeShare(getEffectiveNodeShare());
82-
}
83-
}
8469
} else {
8570
// Update setting now
8671
_setSettingUint(_settingPath, _value);
@@ -98,7 +83,7 @@ contract RocketDAOProtocolSettingsNetwork is RocketDAOProtocolSettings, RocketDA
9883
}
9984

10085
function getMaxNodeShareSecurityCouncilAdder() override public view returns (uint256) {
101-
return getSettingUint("network.node.commission.share.security.council.adder");
86+
return getSettingUint("network.max.node.commission.share.council.adder");
10287
}
10388

10489
function getVoterShare() override public view returns (uint256) {
@@ -194,4 +179,76 @@ contract RocketDAOProtocolSettingsNetwork is RocketDAOProtocolSettings, RocketDA
194179
function getSubmitRewardsEnabled() override external view returns (bool) {
195180
return getSettingBool("network.submit.rewards.enabled");
196181
}
182+
183+
/// @notice Returns a list of addresses allowed to update commission share parameters
184+
function getAllowListedControllers() override public view returns (address[] memory) {
185+
return getSettingAddressList("network.allow.listed.controllers");
186+
}
187+
188+
/// @notice Returns true if the supplied address is one of the allow listed controllers
189+
/// @param _address The address to check for on the allow list
190+
function isAllowListedController(address _address) override public view returns (bool) {
191+
address[] memory allowList = getAllowListedControllers();
192+
for (uint256 i = 0; i < allowList.length; ++i) {
193+
if (allowList[i] == _address) return true;
194+
}
195+
return false;
196+
}
197+
198+
/// @notice Called by an explicitly allowed address to modify the security council adder parameter
199+
/// @param _value New value for the parameter
200+
function setNodeShareSecurityCouncilAdder(uint256 _value) override external onlyAllowListedController {
201+
_setNodeShareSecurityCouncilAdder(_value);
202+
}
203+
204+
/// @notice Called by an explicitly allowed address to modify the node commission share parameter
205+
/// @param _value New value for the parameter
206+
function setNodeCommissionShare(uint256 _value) override external onlyAllowListedController {
207+
_setNodeCommissionShare(_value);
208+
}
209+
210+
/// @notice Called by an explicitly allowed address to modify the voter share parameter
211+
/// @param _value New value for the parameter
212+
function setVoterShare(uint256 _value) override external onlyAllowListedController {
213+
_setVoterShare(_value);
214+
}
215+
216+
/// @dev Internal implementation of setting the node share security council adder parameter
217+
function _setNodeShareSecurityCouncilAdder(uint256 _value) internal {
218+
// Validate input
219+
uint256 maxAdderValue = getSettingUint("network.max.node.commission.share.council.adder");
220+
require(_value <= maxAdderValue, "Value must be <= max value");
221+
uint256 maxVoterValue = getSettingUint("network.voter.share");
222+
require(_value <= maxVoterValue, "Value must be <= voter share");
223+
// Make setting change
224+
_setSettingUint("network.node.commission.share.security.council.adder", _value);
225+
// Sanity check value
226+
require(getRethCommission() <= 1 ether, "rETH Commission must be <= 100%");
227+
// Notify change of UARS parameter for snapshot
228+
RocketNetworkRevenuesInterface rocketNetworkRevenues = RocketNetworkRevenuesInterface(getContractAddress("rocketNetworkRevenues"));
229+
rocketNetworkRevenues.setVoterShare(getEffectiveVoterShare());
230+
rocketNetworkRevenues.setNodeShare(getEffectiveNodeShare());
231+
}
232+
233+
/// @dev Internal implementation of setting the node commission share parameter
234+
function _setNodeCommissionShare(uint256 _value) internal {
235+
// Make setting change
236+
_setSettingUint("network.node.commission.share", _value);
237+
// Sanity check value
238+
require(getRethCommission() <= 1 ether, "rETH Commission must be <= 100%");
239+
// Notify change of UARS parameter for snapshot
240+
RocketNetworkRevenuesInterface rocketNetworkRevenues = RocketNetworkRevenuesInterface(getContractAddress("rocketNetworkRevenues"));
241+
rocketNetworkRevenues.setNodeShare(getEffectiveNodeShare());
242+
}
243+
244+
/// @dev Internal implementation of setting the voter share parameter
245+
function _setVoterShare(uint256 _value) internal {
246+
// Make setting change
247+
_setSettingUint("network.voter.share", _value);
248+
// Sanity check value
249+
require(getRethCommission() <= 1 ether, "rETH Commission must be <= 100%");
250+
// Notify change of UARS parameter for snapshot
251+
RocketNetworkRevenuesInterface rocketNetworkRevenues = RocketNetworkRevenuesInterface(getContractAddress("rocketNetworkRevenues"));
252+
rocketNetworkRevenues.setVoterShare(getEffectiveVoterShare());
253+
}
197254
}

contracts/interface/dao/protocol/RocketDAOProtocolInterface.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface RocketDAOProtocolInterface {
1212
function bootstrapSettingUint(string memory _settingContractName, string memory _settingPath, uint256 _value) external;
1313
function bootstrapSettingBool(string memory _settingContractName, string memory _settingPath, bool _value) external;
1414
function bootstrapSettingAddress(string memory _settingContractName, string memory _settingPath, address _value) external;
15+
function bootstrapSettingAddressList(string memory _settingContractName, string memory _settingPath, address[] calldata _value) external;
1516
function bootstrapSettingClaimers(uint256 _trustedNodePerc, uint256 _protocolPerc, uint256 _nodePerc) external;
1617
function bootstrapSpendTreasury(string memory _invoiceID, address _recipientAddress, uint256 _amount) external;
1718
function bootstrapTreasuryNewContract(string memory _contractName, address _recipientAddress, uint256 _amountPerPeriod, uint256 _periodLength, uint256 _startTime, uint256 _numPeriods) external;

contracts/interface/dao/protocol/RocketDAOProtocolProposalsInterface.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface RocketDAOProtocolProposalsInterface {
99
function proposalSettingUint(string memory _settingContractName, string memory _settingPath, uint256 _value) external;
1010
function proposalSettingBool(string memory _settingContractName, string memory _settingPath, bool _value) external;
1111
function proposalSettingAddress(string memory _settingContractName, string memory _settingPath, address _value) external;
12+
function proposalSettingAddressList(string memory _settingContractName, string memory _settingPath, address[] calldata _value) external;
1213
function proposalSettingRewardsClaimers(uint256 _trustedNodePercent, uint256 _protocolPercent, uint256 _nodePercent) external;
1314

1415
function proposalTreasuryOneTimeSpend(string memory _invoiceID, address _recipientAddress, uint256 _amount) external;

contracts/interface/dao/protocol/settings/RocketDAOProtocolSettingsInterface.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ interface RocketDAOProtocolSettingsInterface {
99
function setSettingBool(string memory _settingPath, bool _value) external;
1010
function getSettingAddress(string memory _settingPath) external view returns (address);
1111
function setSettingAddress(string memory _settingPath, address _value) external;
12+
function setSettingAddressList(string memory _settingPath, address[] calldata _value) external;
13+
function getSettingAddressList(string memory _settingPath) external view returns (address[] memory);
1214
}

0 commit comments

Comments
 (0)