-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathSocketSrc.sol
349 lines (320 loc) · 13 KB
/
SocketSrc.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
347
348
349
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.19;
import "./SocketBase.sol";
/**
* @title SocketSrc
* @dev The SocketSrc contract inherits from SocketBase and handles all the operations that
* happen on the source side. Provides the following functions
* 1. Sending messages from the local chain to a remote chain
* 2. Estimating minFees for message transmission, verification and execution
* 3. Sealing packets and making them ready to be transmitted
*/
abstract contract SocketSrc is SocketBase {
////////////////////////////////////////////////////////
////////////////////// ERRORS //////////////////////////
////////////////////////////////////////////////////////
/**
* @dev Error triggerred when invalid capacitor address is provided
*/
error InvalidCapacitorAddress();
/**
* @dev Error triggerred when siblingPlug is not found
*/
error PlugDisconnected();
////////////////////////////////////////////////////////
////////////////////// EVENTS //////////////////////////
////////////////////////////////////////////////////////
/**
* @notice Emits as soon as a capacitor is sealed
* @param transmitter address of transmitter that sealed this packet(recovered from sig)
* @param packetId packed-packet id
* @param root root of the packet
* @param signature signature of transmitter
*/
event Sealed(
address indexed transmitter,
bytes32 indexed packetId,
uint256 batchSize,
bytes32 root,
bytes signature
);
/**
* @notice emits the message details when a new message arrives at outbound
* @param localChainSlug local chain slug
* @param localPlug local plug address
* @param dstChainSlug remote chain slug
* @param dstPlug remote plug address
* @param msgId message id packed with remoteChainSlug and nonce
* @param minMsgGasLimit gas limit needed to execute the inbound at remote
* @param payload the data which will be used by inbound at remote
*/
event MessageOutbound(
uint32 localChainSlug,
address localPlug,
uint32 dstChainSlug,
address dstPlug,
bytes32 msgId,
uint256 minMsgGasLimit,
bytes32 executionParams,
bytes32 transmissionParams,
bytes payload,
Fees fees
);
/**
* @notice To send message to a connected remote chain. Should only be called by a plug.
* @param siblingChainSlug_ the remote chain slug
* @param minMsgGasLimit_ the minimum gas-limit needed to execute the payload on remote
* @param executionParams_ a 32 bytes param to add details for execution, for eg: fees to be paid for execution
* @param transmissionParams_ a 32 bytes param to add extra details for transmission
* @param payload_ bytes to be delivered to the Plug on the siblingChainSlug_
*/
function outbound(
uint32 siblingChainSlug_,
uint256 minMsgGasLimit_,
bytes32 executionParams_,
bytes32 transmissionParams_,
bytes calldata payload_
) external payable override returns (bytes32 msgId) {
PlugConfig memory plugConfig;
// looks up the sibling plug address using the msg.sender as the local plug address
plugConfig.siblingPlug = _plugConfigs[msg.sender][siblingChainSlug_]
.siblingPlug;
// if no sibling plug is found for the given chain slug, revert
if (plugConfig.siblingPlug == address(0)) revert PlugDisconnected();
// fetches auxillary details for the message from the plug config
plugConfig.capacitor__ = _plugConfigs[msg.sender][siblingChainSlug_]
.capacitor__;
plugConfig.outboundSwitchboard__ = _plugConfigs[msg.sender][
siblingChainSlug_
].outboundSwitchboard__;
// creates a unique ID for the message
msgId = _encodeMsgId(plugConfig.siblingPlug);
// validate if caller has send enough fees, if yes, send fees to execution manager
// for parties to claim later
ISocket.Fees memory fees = _validateAndSendFees(
minMsgGasLimit_,
uint256(payload_.length),
executionParams_,
transmissionParams_,
plugConfig.outboundSwitchboard__,
plugConfig.capacitor__.getMaxPacketLength(),
siblingChainSlug_
);
ISocket.MessageDetails memory messageDetails = ISocket.MessageDetails({
msgId: msgId,
minMsgGasLimit: minMsgGasLimit_,
executionParams: executionParams_,
payload: payload_,
executionFee: fees.executionFee
});
// create a compressed data-struct called PackedMessage
// which has the message payload and some configuration details
bytes32 packedMessage = hasher__.packMessage(
chainSlug,
msg.sender,
siblingChainSlug_,
plugConfig.siblingPlug,
messageDetails
);
// finally add packedMessage to the capacitor to generate new root
plugConfig.capacitor__.addPackedMessage(packedMessage);
emit MessageOutbound(
chainSlug,
msg.sender,
siblingChainSlug_,
plugConfig.siblingPlug,
msgId,
minMsgGasLimit_,
executionParams_,
transmissionParams_,
payload_,
fees
);
}
/**
* @notice Validates if enough fee is provided for message execution. If yes, fees is sent and stored in execution manager.
* @param minMsgGasLimit_ the min gas-limit of the message.
* @param payloadSize_ The byte length of payload of the message.
* @param executionParams_ The extraParams required for execution.
* @param transmissionParams_ The extraParams required for transmission.
* @param switchboard_ The address of the switchboard through which the message is sent.
* @param maxPacketLength_ The maxPacketLength for the capacitor used. Used for calculating transmission Fees.
* @param siblingChainSlug_ The slug of the destination chain for the message.
*/
function _validateAndSendFees(
uint256 minMsgGasLimit_,
uint256 payloadSize_,
bytes32 executionParams_,
bytes32 transmissionParams_,
ISwitchboard switchboard_,
uint256 maxPacketLength_,
uint32 siblingChainSlug_
) internal returns (ISocket.Fees memory fees) {
uint128 verificationFeePerMessage;
// switchboard is plug configured and this is an external untrusted call
(
fees.switchboardFees,
verificationFeePerMessage
) = _getSwitchboardMinFees(siblingChainSlug_, switchboard_);
// deposits msg.value to execution manager and checks if enough fees is provided
(fees.executionFee, fees.transmissionFees) = executionManager__
.payAndCheckFees{value: msg.value}(
minMsgGasLimit_,
payloadSize_,
executionParams_,
transmissionParams_,
siblingChainSlug_,
fees.switchboardFees / uint128(maxPacketLength_),
verificationFeePerMessage,
address(transmitManager__),
address(switchboard_),
maxPacketLength_
);
}
/**
* @notice Retrieves the minimum fees required for a message with a specified gas limit and destination chain.
* @param minMsgGasLimit_ The gas limit of the message.
* @param payloadSize_ The byte length of payload of the message.
* @param executionParams_ The extraParams required for execution.
* @param siblingChainSlug_ The slug of the destination chain for the message.
* @param plug_ The address of the plug through which the message is sent.
* @return totalFees The minimum fees required for the specified message.
*/
function getMinFees(
uint256 minMsgGasLimit_,
uint256 payloadSize_,
bytes32 executionParams_,
bytes32 transmissionParams_,
uint32 siblingChainSlug_,
address plug_
) external view override returns (uint256 totalFees) {
ICapacitor capacitor__ = _plugConfigs[plug_][siblingChainSlug_]
.capacitor__;
uint256 maxPacketLength = capacitor__.getMaxPacketLength();
(
uint128 transmissionFees,
uint128 switchboardFees,
uint128 executionFees
) = _getAllMinFees(
minMsgGasLimit_,
payloadSize_,
executionParams_,
transmissionParams_,
siblingChainSlug_,
_plugConfigs[plug_][siblingChainSlug_].outboundSwitchboard__,
maxPacketLength
);
totalFees = transmissionFees + switchboardFees + executionFees;
}
/**
* @notice Retrieves the minimum fees required for switchboard.
* @param siblingChainSlug_ The slug of the destination chain for the message.
* @param switchboard__ The switchboard address for which fees is retrieved.
* @return switchboardFees fees required for message verification
*/
function _getSwitchboardMinFees(
uint32 siblingChainSlug_,
ISwitchboard switchboard__
)
internal
view
returns (uint128 switchboardFees, uint128 verificationOverheadFees)
{
(switchboardFees, verificationOverheadFees) = switchboard__.getMinFees(
siblingChainSlug_
);
}
/**
* @notice Retrieves the minimum fees required for a message with a specified gas limit and destination chain.
* @param minMsgGasLimit_ The gas limit of the message.
* @param payloadSize_ The byte length of payload of the message.
* @param executionParams_ The extraParams required for execution.
* @param siblingChainSlug_ The slug of the destination chain for the message.
* @param switchboard__ The address of the switchboard through which the message is sent.
*/
function _getAllMinFees(
uint256 minMsgGasLimit_,
uint256 payloadSize_,
bytes32 executionParams_,
bytes32 transmissionParams_,
uint32 siblingChainSlug_,
ISwitchboard switchboard__,
uint256 maxPacketLength_
)
internal
view
returns (
uint128 transmissionFees,
uint128 switchboardFees,
uint128 executionFees
)
{
uint128 verificationOverheadFees;
uint128 msgExecutionFee;
(switchboardFees, verificationOverheadFees) = _getSwitchboardMinFees(
siblingChainSlug_,
switchboard__
);
switchboardFees /= uint128(maxPacketLength_);
(msgExecutionFee, transmissionFees) = executionManager__
.getExecutionTransmissionMinFees(
minMsgGasLimit_,
payloadSize_,
executionParams_,
transmissionParams_,
siblingChainSlug_,
address(transmitManager__)
);
transmissionFees /= uint128(maxPacketLength_);
executionFees = msgExecutionFee + verificationOverheadFees;
}
/**
* @notice seals data in capacitor for specific batchSize
* @param batchSize_ size of batch to be sealed
* @param capacitorAddress_ address of capacitor
* @param signature_ signed Data needed for verification
*/
function seal(
uint256 batchSize_,
address capacitorAddress_,
bytes calldata signature_
) external payable override {
uint32 siblingChainSlug = capacitorToSlug[capacitorAddress_];
if (siblingChainSlug == 0) revert InvalidCapacitorAddress();
(bytes32 root, uint64 packetCount) = ICapacitor(capacitorAddress_)
.sealPacket(batchSize_);
bytes32 packetId = _encodePacketId(capacitorAddress_, packetCount);
(address transmitter, bool isTransmitter) = transmitManager__
.checkTransmitter(
siblingChainSlug,
keccak256(
abi.encode(version, siblingChainSlug, packetId, root)
),
signature_
);
if (!isTransmitter) revert InvalidTransmitter();
emit Sealed(transmitter, packetId, batchSize_, root, signature_);
}
// Packs the local plug, local chain slug, remote chain slug and nonce
// globalMessageCount++ will take care of msg id overflow as well
// msgId(256) = localChainSlug(32) | siblingPlug_(160) | nonce(64)
function _encodeMsgId(address siblingPlug_) internal returns (bytes32) {
return
bytes32(
(uint256(chainSlug) << 224) |
(uint256(uint160(siblingPlug_)) << 64) |
globalMessageCount++
);
}
function _encodePacketId(
address capacitorAddress_,
uint64 packetCount_
) internal view returns (bytes32) {
return
bytes32(
(uint256(chainSlug) << 224) |
(uint256(uint160(capacitorAddress_)) << 64) |
packetCount_
);
}
}