-
Notifications
You must be signed in to change notification settings - Fork 16
/
Dispatch.sol
346 lines (305 loc) · 13.5 KB
/
Dispatch.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
// SPDX-License-Identifier: UNLICENSED
// See Forta Network License: https://github.com/forta-network/forta-contracts/blob/master/LICENSE.md
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../BaseComponentUpgradeable.sol";
import "../agents/AgentRegistry.sol";
import "../scanners/ScannerRegistry.sol";
import "../scanner_pools/ScannerPoolRegistry.sol";
contract Dispatch is BaseComponentUpgradeable {
using EnumerableSet for EnumerableSet.UintSet;
string public constant version = "0.1.5";
AgentRegistry private _agents;
/// @custom:oz-renamed-from _scanners
ScannerRegistry private _scanners_deprecated;
mapping(uint256 => EnumerableSet.UintSet) private scannerToAgents;
mapping(uint256 => EnumerableSet.UintSet) private agentToScanners;
ScannerPoolRegistry private _scannerPools;
error Disabled(string name);
error InvalidId(string name, uint256 id);
event SetAgentRegistry(address registry);
event SetScannerRegistry(address registry);
event SetScannerPoolRegistry(address registry);
event AlreadyLinked(uint256 agentId, uint256 scannerId, bool enable);
event Link(uint256 agentId, uint256 scannerId, bool enable);
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address forwarder) initializer ForwardedContext(forwarder) {}
/**
* @notice Initializer method, access point to initialize inheritance tree.
* @param __manager address of AccessManager.
* @param __agents address of AgentRegistry.
* @param __scanners address of ScannerRegistry.
* @param __scannerPools address of ScannerPoolRegistry.
*/
function initialize(
address __manager,
address __agents,
address __scanners,
address __scannerPools
) public initializer {
__BaseComponentUpgradeable_init(__manager);
_setAgentRegistry(__agents);
_setScannerRegistry(__scanners);
_setScannerPoolRegistry(__scannerPools);
}
function agentRegistry() public view returns (AgentRegistry) {
return _agents;
}
function scannerRegistry() public view returns (ScannerRegistry) {
return _scanners_deprecated;
}
function scannerPoolRegistry() public view returns (ScannerPoolRegistry) {
return _scannerPools;
}
/**
* @notice Get total agents linked to a scanner.
* @dev helper for external iteration.
* @param scannerId address of the scanner converted to uint256
* @return total agents linked to a scanner
*/
function numAgentsFor(uint256 scannerId) public view returns (uint256) {
return scannerToAgents[scannerId].length();
}
/**
* @notice Get total scanners where an agent is running in.
* @dev helper for external iteration.
* @param agentId ERC721 token id of the agent.
* @return total scanners running an scanner
*/
function numScannersFor(uint256 agentId) public view returns (uint256) {
return agentToScanners[agentId].length();
}
/**
* @notice Get agentId linked to a scanner in certain position.
* @dev helper for external iteration.
* @param scannerId address of the scanner converted to uint256
* @param pos index for iteration.
* @return ERC721 token id of the agent.
*/
function agentAt(uint256 scannerId, uint256 pos) public view returns (uint256) {
return scannerToAgents[scannerId].at(pos);
}
/**
* @notice Get data of an agent linked to a scanner at a certain position.
* @dev helper for external iteration.
* @param scannerId address of the scanner converted to uint256
* @param pos index for iteration.
* @return registered bool if agent exists, false otherwise.
* @return owner address.
* @return agentId ERC721 token id of the agent.
* @return agentVersion agent version number.
* @return metadata IPFS pointer for agent metadata.
* @return chainIds ordered array of chainId were the agent wants to run.
* @return enabled bool if agent is enabled, false otherwise.
* @return disabledFlags 0 if not disabled, Permission that disabled the scnner otherwise.
*/
function agentRefAt(uint256 scannerId, uint256 pos)
external
view
returns (
bool registered,
address owner,
uint256 agentId,
uint256 agentVersion,
string memory metadata,
uint256[] memory chainIds,
bool enabled,
uint256 disabledFlags
)
{
agentId = agentAt(scannerId, pos);
(registered, owner, agentVersion, metadata, chainIds, enabled, disabledFlags) = _agents.getAgentState(agentId);
return (registered, owner, agentId, agentVersion, metadata, chainIds, enabled, disabledFlags);
}
/**
* @notice Get scannerId running an agent at a certain position.
* @dev helper for external iteration.
* @param agentId ERC721 token id of the scanner.
* @param pos index for iteration.
* @return ERC721 token id of the scanner.
*/
function scannerAt(uint256 agentId, uint256 pos) public view returns (uint256) {
return agentToScanners[agentId].at(pos);
}
/**
* @notice Get data of ascanner running an agent at a certain position.
* @dev helper for external iteration.
* @param agentId ERC721 token id of the agent.
* @param pos index for iteration.
* @return registered true if scanner is registered.
* @return scannerId ERC721 token id of the scanner.
* @return owner address.
* @return chainId that the scanner monitors.
* @return metadata IPFS pointer for agent metadata.
* @return operational true if scanner is not disabled and staked over min, false otherwise.
* @return disabled true if disabled by ScannerPool or scanner itself.
*/
function scannerRefAt(uint256 agentId, uint256 pos)
external
view
returns (
bool registered,
uint256 scannerId,
address owner,
uint256 chainId,
string memory metadata,
bool operational,
bool disabled
)
{
scannerId = scannerAt(agentId, pos);
(registered, owner, chainId, metadata, operational, disabled) = _getScannerState(scannerId);
return (registered, scannerId, owner, chainId, metadata, operational, disabled);
}
/// Returns true if scanner and agents are linked, false otherwise.
function areTheyLinked(uint256 agentId, uint256 scannerId) external view returns (bool) {
return scannerToAgents[scannerId].contains(agentId) && agentToScanners[agentId].contains(scannerId);
}
/**
* @notice Assigns the job of running an agent to a scanner.
* @dev currently only allowed for DISPATCHER_ROLE (Assigner software).
* @dev emits Link(agentId, scannerId, true) event.
* @param agentId ERC721 token id of the agent.
* @param scannerId address of the scanner converted to uint256
*/
function link(uint256 agentId, uint256 scannerId) public onlyRole(DISPATCHER_ROLE) {
if (!_agents.isEnabled(agentId)) revert Disabled("Agent");
if (!_isScannerOperational(scannerId)) revert Disabled("Scanner");
if (!scannerToAgents[scannerId].add(agentId) || !agentToScanners[agentId].add(scannerId)) {
emit AlreadyLinked(agentId, scannerId, true);
} else {
emit Link(agentId, scannerId, true);
}
}
/**
* @notice Unassigns the job of running an agent to a scanner.
* @dev currently only allowed for DISPATCHER_ROLE (Assigner software).
* @dev emits Link(agentId, scannerId, false) event.
* @param agentId ERC721 token id of the agent.
* @param scannerId address of the scanner converted to uint256
*/
function unlink(uint256 agentId, uint256 scannerId) public onlyRole(DISPATCHER_ROLE) {
if (!_agents.isRegistered(agentId)) revert InvalidId("Agent", agentId);
if (!_isScannerRegistered(scannerId)) revert InvalidId("Scanner", scannerId);
if (!scannerToAgents[scannerId].remove(agentId) || !agentToScanners[agentId].remove(scannerId)) {
emit AlreadyLinked(agentId, scannerId, false);
} else {
emit Link(agentId, scannerId, false);
}
}
/**
* @notice Sets agent registry address.
* @dev only DEFAULT_ADMIN_ROLE (governance).
* @param newAgentRegistry agent of the new AgentRegistry.
*/
function setAgentRegistry(address newAgentRegistry) public onlyRole(DEFAULT_ADMIN_ROLE) {
_setAgentRegistry(newAgentRegistry);
}
function _setAgentRegistry(address newAgentRegistry) private {
if (newAgentRegistry == address(0)) revert ZeroAddress("newAgentRegistry");
_agents = AgentRegistry(newAgentRegistry);
emit SetAgentRegistry(newAgentRegistry);
}
/**
* @notice Sets scanner registry address.
* @dev only DEFAULT_ADMIN_ROLE (governance).
* @param newScannerRegistry agent of the new ScannerRegistry.
*/
function setScannerRegistry(address newScannerRegistry) public onlyRole(DEFAULT_ADMIN_ROLE) {
_setScannerRegistry(newScannerRegistry);
}
function _setScannerRegistry(address newScannerRegistry) private {
if (newScannerRegistry == address(0)) revert ZeroAddress("newScannerRegistry");
_scanners_deprecated = ScannerRegistry(newScannerRegistry);
emit SetScannerRegistry(newScannerRegistry);
}
/**
* @notice Sets ScannerPool registry address.
* @dev only DEFAULT_ADMIN_ROLE (governance).
* @param newScannerPoolRegistry agent of the new ScannerRegistry.
*/
function setScannerPoolRegistry(address newScannerPoolRegistry) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setScannerPoolRegistry(newScannerPoolRegistry);
}
function _setScannerPoolRegistry(address newScannerPoolRegistry) private {
if (newScannerPoolRegistry == address(0)) revert ZeroAddress("newScannerPoolRegistry");
_scannerPools = ScannerPoolRegistry(newScannerPoolRegistry);
emit SetScannerPoolRegistry(newScannerPoolRegistry);
}
/**
* Method to hash the amount of scanners an agent is running in, and their status
* @dev method marked for deprecation in next version.
*/
function agentHash(uint256 agentId) external view returns (uint256 length, bytes32 manifest) {
uint256[] memory scanners = agentToScanners[agentId].values();
bool[] memory enabled = new bool[](scanners.length);
for (uint256 i = 0; i < scanners.length; i++) {
enabled[i] = _isScannerOperational(scanners[i]);
}
return (scanners.length, keccak256(abi.encodePacked(scanners, enabled)));
}
/**
* @dev method used by Scanner Node software to know if their list of assigned agents has changed,
* their enabled state or version has changed so they can start managing changes
* (loading new agent images, removing not assigned agents, updating agents...).
* @param scannerId address of the scanner converted to uint256
* @return length amount of agents.
* @return manifest keccak256 of list of agents, list of agentVersion and list of enabled states.
*/
function scannerHash(uint256 scannerId) external view returns (uint256 length, bytes32 manifest) {
uint256[] memory agents = scannerToAgents[scannerId].values();
uint256[] memory agentVersion = new uint256[](agents.length);
bool[] memory enabled = new bool[](agents.length);
for (uint256 i = 0; i < agents.length; i++) {
(, , agentVersion[i], , ) = _agents.getAgent(agents[i]);
enabled[i] = _agents.isEnabled(agents[i]);
}
return (agents.length, keccak256(abi.encodePacked(agents, agentVersion, enabled)));
}
function _isScannerOperational(uint256 scannerId) internal view returns (bool) {
if (_scanners_deprecated.hasMigrationEnded()) {
return _scannerPools.isScannerOperational(address(uint160(scannerId)));
} else {
return _scanners_deprecated.isEnabled(scannerId);
}
}
function _isScannerRegistered(uint256 scannerId) internal view returns (bool) {
if (_scanners_deprecated.hasMigrationEnded()) {
return _scannerPools.isScannerRegistered(address(uint160(scannerId)));
} else {
return _scanners_deprecated.isRegistered(scannerId);
}
}
function _getScannerState(uint256 scannerId)
internal
view
returns (
bool registered,
address owner,
uint256 chainId,
string memory metadata,
bool operational,
bool disabled
)
{
if (_scanners_deprecated.hasMigrationEnded()) {
return _scannerPools.getScannerState(address(uint160(scannerId)));
} else {
uint256 disabledFlags;
(registered, owner, chainId, metadata, operational, disabledFlags) = _scanners_deprecated.getScannerState(scannerId);
return (registered, owner, chainId, metadata, operational, disabledFlags != 0);
}
}
/**
* 50
* 1 _agents;
* 1 _scanners_deprecated;
* 1 scannerToAgents
* 1 agentToScanners
* 48 (mistakenly deployed with 48 in version 0.1.4, so we start counting here again. This contract is the last of its inheritance chain, so it's fine.)
* - 1 _scannerPools
* --------------------------
* 47 __gap
*/
uint256[47] private __gap;
}