2
2
3
3
pragma solidity ^ 0.7.3 ;
4
4
5
- import "./IManaged.sol " ;
6
5
import "./IController.sol " ;
6
+
7
7
import "../curation/ICuration.sol " ;
8
8
import "../epochs/IEpochManager.sol " ;
9
9
import "../rewards/IRewardsManager.sol " ;
@@ -12,19 +12,33 @@ import "../token/IGraphToken.sol";
12
12
13
13
/**
14
14
* @title Graph Managed contract
15
- * @dev The Managed contract provides an interface for contracts to interact with the Controller
15
+ * @dev The Managed contract provides an interface to interact with the Controller.
16
+ * It also provides local caching for contract addresses. This mechanism relies on calling the
17
+ * public `syncAllContracts()` function whenever a contract changes in the controller.
18
+ *
16
19
* Inspired by Livepeer:
17
20
* https://github.com/livepeer/protocol/blob/streamflow/contracts/Controller.sol
18
21
*/
19
22
contract Managed {
23
+ // -- State --
24
+
20
25
// Controller that contract is registered with
21
26
IController public controller;
22
- mapping (bytes32 => address ) public addressCache;
27
+ mapping (bytes32 => address ) private addressCache;
23
28
uint256 [10 ] private __gap;
24
29
30
+ // -- Events --
31
+
25
32
event ParameterUpdated (string param );
26
33
event SetController (address controller );
27
34
35
+ /**
36
+ * @dev Emitted when contract with `nameHash` is synced to `contractAddress`.
37
+ */
38
+ event ContractSynced (bytes32 indexed nameHash , address contractAddress );
39
+
40
+ // -- Modifiers --
41
+
28
42
function _notPartialPaused () internal view {
29
43
require (! controller.paused (), "Paused " );
30
44
require (! controller.partialPaused (), "Partial-paused " );
@@ -38,6 +52,10 @@ contract Managed {
38
52
require (msg .sender == controller.getGovernor (), "Caller must be Controller governor " );
39
53
}
40
54
55
+ function _onlyController () internal view {
56
+ require (msg .sender == address (controller), "Caller must be Controller " );
57
+ }
58
+
41
59
modifier notPartialPaused {
42
60
_notPartialPaused ();
43
61
_;
@@ -48,26 +66,29 @@ contract Managed {
48
66
_;
49
67
}
50
68
51
- // Check if sender is controller
69
+ // Check if sender is controller.
52
70
modifier onlyController () {
53
- require ( msg . sender == address (controller), " Caller must be Controller " );
71
+ _onlyController ( );
54
72
_;
55
73
}
56
74
75
+ // Check if sender is the governor.
57
76
modifier onlyGovernor () {
58
77
_onlyGovernor ();
59
78
_;
60
79
}
61
80
81
+ // -- Functions --
82
+
62
83
/**
63
- * @dev Initialize the controller
84
+ * @dev Initialize the controller.
64
85
*/
65
86
function _initialize (address _controller ) internal {
66
87
_setController (_controller);
67
88
}
68
89
69
90
/**
70
- * @notice Set Controller. Only callable by current controller
91
+ * @notice Set Controller. Only callable by current controller.
71
92
* @param _controller Controller contract address
72
93
*/
73
94
function setController (address _controller ) external onlyController {
@@ -85,42 +106,81 @@ contract Managed {
85
106
}
86
107
87
108
/**
88
- * @dev Return Curation interface
109
+ * @dev Return Curation interface.
89
110
* @return Curation contract registered with Controller
90
111
*/
91
112
function curation () internal view returns (ICuration) {
92
- return ICuration (controller. getContractProxy (keccak256 ("Curation " )));
113
+ return ICuration (_resolveContract (keccak256 ("Curation " )));
93
114
}
94
115
95
116
/**
96
- * @dev Return EpochManager interface
117
+ * @dev Return EpochManager interface.
97
118
* @return Epoch manager contract registered with Controller
98
119
*/
99
120
function epochManager () internal view returns (IEpochManager) {
100
- return IEpochManager (controller. getContractProxy (keccak256 ("EpochManager " )));
121
+ return IEpochManager (_resolveContract (keccak256 ("EpochManager " )));
101
122
}
102
123
103
124
/**
104
- * @dev Return RewardsManager interface
125
+ * @dev Return RewardsManager interface.
105
126
* @return Rewards manager contract registered with Controller
106
127
*/
107
128
function rewardsManager () internal view returns (IRewardsManager) {
108
- return IRewardsManager (controller. getContractProxy (keccak256 ("RewardsManager " )));
129
+ return IRewardsManager (_resolveContract (keccak256 ("RewardsManager " )));
109
130
}
110
131
111
132
/**
112
- * @dev Return Staking interface
133
+ * @dev Return Staking interface.
113
134
* @return Staking contract registered with Controller
114
135
*/
115
136
function staking () internal view returns (IStaking) {
116
- return IStaking (controller. getContractProxy (keccak256 ("Staking " )));
137
+ return IStaking (_resolveContract (keccak256 ("Staking " )));
117
138
}
118
139
119
140
/**
120
- * @dev Return GraphToken interface
141
+ * @dev Return GraphToken interface.
121
142
* @return Graph token contract registered with Controller
122
143
*/
123
144
function graphToken () internal view returns (IGraphToken) {
124
- return IGraphToken (controller.getContractProxy (keccak256 ("GraphToken " )));
145
+ return IGraphToken (_resolveContract (keccak256 ("GraphToken " )));
146
+ }
147
+
148
+ /**
149
+ * @dev Resolve a contract address from the cache or the Controller if not found.
150
+ * @return Address of the contract
151
+ */
152
+ function _resolveContract (bytes32 _nameHash ) internal view returns (address ) {
153
+ address contractAddress = addressCache[_nameHash];
154
+ if (contractAddress == address (0 )) {
155
+ contractAddress = controller.getContractProxy (_nameHash);
156
+ }
157
+ return contractAddress;
158
+ }
159
+
160
+ /**
161
+ * @dev Cache a contract address from the Controller registry.
162
+ * @param _name Name of the contract to sync into the cache
163
+ */
164
+ function _syncContract (string memory _name ) internal {
165
+ bytes32 nameHash = keccak256 (abi.encodePacked (_name));
166
+ address contractAddress = controller.getContractProxy (nameHash);
167
+ if (addressCache[nameHash] != contractAddress) {
168
+ addressCache[nameHash] = contractAddress;
169
+ emit ContractSynced (nameHash, contractAddress);
170
+ }
171
+ }
172
+
173
+ /**
174
+ * @dev Sync protocol contract addresses from the Controller registry.
175
+ * This function will cache all the contracts using the latest addresses
176
+ * Anyone can call the function whenever a Proxy contract change in the
177
+ * controller to ensure the protocol is using the latest version
178
+ */
179
+ function syncAllContracts () external {
180
+ _syncContract ("Curation " );
181
+ _syncContract ("EpochManager " );
182
+ _syncContract ("RewardsManager " );
183
+ _syncContract ("Staking " );
184
+ _syncContract ("GraphToken " );
125
185
}
126
186
}
0 commit comments