-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathWatcherPrecompileConfig.sol
200 lines (171 loc) · 7.45 KB
/
WatcherPrecompileConfig.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
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.21;
import "./WatcherPrecompileLimits.sol";
import {ECDSA} from "solady/utils/ECDSA.sol";
import "solady/utils/Initializable.sol";
import {IWatcherPrecompileConfig} from "../../interfaces/IWatcherPrecompileConfig.sol";
/// @title WatcherPrecompileConfig
/// @notice Configuration contract for the Watcher Precompile system
/// @dev Handles the mapping between networks, plugs, and app gateways for payload execution
contract WatcherPrecompileConfig is
IWatcherPrecompileConfig,
Initializable,
AccessControl,
AddressResolverUtil
{
// slot 52: evmxSlug
/// @notice The chain slug of the watcher precompile
uint32 public evmxSlug;
// slot 55: _plugConfigs
/// @notice Maps network and plug to their configuration
/// @dev chainSlug => plug => PlugConfig
mapping(uint32 => mapping(address => PlugConfig)) internal _plugConfigs;
// slot 56: switchboards
/// @notice Maps chain slug to their associated switchboard
/// @dev chainSlug => sb type => switchboard address
mapping(uint32 => mapping(bytes32 => address)) public switchboards;
// slot 57: sockets
/// @notice Maps chain slug to their associated socket
/// @dev chainSlug => socket address
mapping(uint32 => address) public sockets;
// slot 58: contractFactoryPlug
/// @notice Maps chain slug to their associated contract factory plug
/// @dev chainSlug => contract factory plug address
mapping(uint32 => address) public contractFactoryPlug;
// slot 59: feesPlug
/// @notice Maps chain slug to their associated fees plug
/// @dev chainSlug => fees plug address
mapping(uint32 => address) public feesPlug;
// slot 60: isNonceUsed
/// @notice Maps nonce to whether it has been used
/// @dev signatureNonce => isValid
mapping(uint256 => bool) public isNonceUsed;
// slot 61: isValidPlug
// appGateway => chainSlug => plug => isValid
mapping(address => mapping(uint32 => mapping(address => bool))) public isValidPlug;
/// @notice Emitted when a new plug is configured for an app gateway
/// @param appGateway The address of the app gateway
/// @param chainSlug The identifier of the destination network
/// @param plug The address of the plug
event PlugAdded(address appGateway, uint32 chainSlug, address plug);
/// @notice Emitted when a switchboard is set for a network
/// @param chainSlug The identifier of the network
/// @param sbType The type of switchboard
/// @param switchboard The address of the switchboard
event SwitchboardSet(uint32 chainSlug, bytes32 sbType, address switchboard);
/// @notice Emitted when contracts are set for a network
/// @param chainSlug The identifier of the network
/// @param socket The address of the socket
/// @param contractFactoryPlug The address of the contract factory plug
/// @param feesPlug The address of the fees plug
event OnChainContractSet(
uint32 chainSlug,
address socket,
address contractFactoryPlug,
address feesPlug
);
error InvalidGateway();
error InvalidSwitchboard();
/// @notice Initial initialization (version 1)
function initialize(
address owner_,
address addressResolver_,
uint32 evmxSlug_
) public reinitializer(1) {
_setAddressResolver(addressResolver_);
_initializeOwner(owner_);
evmxSlug = evmxSlug_;
}
/// @notice Emitted when a plug is set as valid for an app gateway
/// @notice Configures app gateways with their respective plugs and switchboards
/// @param configs_ Array of configurations containing app gateway, network, plug, and switchboard details
/// @dev Only callable by the contract owner
/// @dev This helps in verifying that plugs are called by respective app gateways
function setAppGateways(
AppGatewayConfig[] memory configs_,
uint256 signatureNonce_,
bytes memory signature_
) external {
_isWatcherSignatureValid(
abi.encode(this.setAppGateways.selector, configs_),
signatureNonce_,
signature_
);
for (uint256 i = 0; i < configs_.length; i++) {
// Store the plug configuration for this network and plug
_plugConfigs[configs_[i].chainSlug][configs_[i].plug] = PlugConfig({
appGateway: configs_[i].appGateway,
switchboard: configs_[i].switchboard
});
emit PlugAdded(configs_[i].appGateway, configs_[i].chainSlug, configs_[i].plug);
}
}
/// @notice Sets the switchboard for a network
/// @param chainSlug_ The identifier of the network
function setOnChainContracts(
uint32 chainSlug_,
address socket_,
address contractFactoryPlug_,
address feesPlug_
) external onlyOwner {
sockets[chainSlug_] = socket_;
contractFactoryPlug[chainSlug_] = contractFactoryPlug_;
feesPlug[chainSlug_] = feesPlug_;
emit OnChainContractSet(chainSlug_, socket_, contractFactoryPlug_, feesPlug_);
}
/// @notice Sets the switchboard for a network
/// @param chainSlug_ The identifier of the network
/// @param switchboard_ The address of the switchboard
function setSwitchboard(
uint32 chainSlug_,
bytes32 sbType_,
address switchboard_
) external onlyOwner {
switchboards[chainSlug_][sbType_] = switchboard_;
emit SwitchboardSet(chainSlug_, sbType_, switchboard_);
}
// @dev app gateway can set the valid plugs for each chain slug
function setIsValidPlug(uint32 chainSlug_, address plug_, bool isValid_) external {
isValidPlug[msg.sender][chainSlug_][plug_] = isValid_;
}
/// @notice Retrieves the configuration for a specific plug on a network
/// @param chainSlug_ The identifier of the network
/// @param plug_ The address of the plug
/// @return The app gateway address and switchboard address for the plug
/// @dev Returns zero addresses if configuration doesn't exist
function getPlugConfigs(
uint32 chainSlug_,
address plug_
) public view returns (address, address) {
return (
_plugConfigs[chainSlug_][plug_].appGateway,
_plugConfigs[chainSlug_][plug_].switchboard
);
}
function verifyConnections(
uint32 chainSlug_,
address target_,
address appGateway_,
address switchboard_
) external view {
// todo: revisit this
// if target is contractFactoryPlug, return
if (target_ == contractFactoryPlug[chainSlug_]) return;
(address appGateway, address switchboard) = getPlugConfigs(chainSlug_, target_);
if (appGateway != appGateway_) revert InvalidGateway();
if (switchboard != switchboard_) revert InvalidSwitchboard();
}
function _isWatcherSignatureValid(
bytes memory digest_,
uint256 signatureNonce_,
bytes memory signature_
) internal {
if (isNonceUsed[signatureNonce_]) revert NonceUsed();
isNonceUsed[signatureNonce_] = true;
bytes32 digest = keccak256(abi.encode(address(this), evmxSlug, signatureNonce_, digest_));
digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest));
// recovered signer is checked for the valid roles later
address signer = ECDSA.recover(digest, signature_);
if (signer != owner()) revert InvalidWatcherSignature();
}
}