This repository was archived by the owner on May 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathBridgeMessage.sol
More file actions
397 lines (360 loc) · 11.4 KB
/
Copy pathBridgeMessage.sol
File metadata and controls
397 lines (360 loc) · 11.4 KB
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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
// ============ External Imports ============
import {TypedMemView} from "@summa-tx/memview-sol/contracts/TypedMemView.sol";
library BridgeMessage {
// ============ Libraries ============
using TypedMemView for bytes;
using TypedMemView for bytes29;
// ============ Enums ============
// WARNING: do NOT re-write the numbers / order
// of message types in an upgrade;
// will cause in-flight messages to be mis-interpreted
enum Types {
Invalid, // 0
TokenId, // 1
Message, // 2
Transfer, // 3
FastTransfer // 4
}
// ============ Structs ============
// Tokens are identified by a TokenId:
// domain - 4 byte chain ID of the chain from which the token originates
// id - 32 byte identifier of the token address on the origin chain, in that chain's address format
struct TokenId {
uint32 domain;
bytes32 id;
}
// ============ Constants ============
uint256 private constant TOKEN_ID_LEN = 36; // 4 bytes domain + 32 bytes id
uint256 private constant IDENTIFIER_LEN = 1;
uint256 private constant TRANSFER_LEN = 97; // 1 byte identifier + 32 bytes recipient + 32 bytes amount + 32 bytes detailsHash
// ============ Modifiers ============
/**
* @notice Asserts a message is of type `_t`
* @param _view The message
* @param _t The expected type
*/
modifier typeAssert(bytes29 _view, Types _t) {
_view.assertType(uint40(_t));
_;
}
// ============ Internal Functions ============
/**
* @notice Checks that Action is valid type
* @param _action The action
* @return TRUE if action is valid
*/
function isValidAction(bytes29 _action) internal pure returns (bool) {
return isTransfer(_action) || isFastTransfer(_action);
}
/**
* @notice Checks that view is a valid message length
* @param _view The bytes string
* @return TRUE if message is valid
*/
function isValidMessageLength(bytes29 _view) internal pure returns (bool) {
uint256 _len = _view.len();
return _len == TOKEN_ID_LEN + TRANSFER_LEN;
}
/**
* @notice Formats an action message
* @param _tokenId The token ID
* @param _action The action
* @return The formatted message
*/
function formatMessage(bytes29 _tokenId, bytes29 _action)
internal
view
typeAssert(_tokenId, Types.TokenId)
returns (bytes memory)
{
require(isValidAction(_action), "!action");
bytes29[] memory _views = new bytes29[](2);
_views[0] = _tokenId;
_views[1] = _action;
return TypedMemView.join(_views);
}
/**
* @notice Returns the type of the message
* @param _view The message
* @return The type of the message
*/
function messageType(bytes29 _view) internal pure returns (Types) {
return Types(uint8(_view.typeOf()));
}
/**
* @notice Checks that the message is of the specified type
* @param _type the type to check for
* @param _action The message
* @return True if the message is of the specified type
*/
function isType(bytes29 _action, Types _type) internal pure returns (bool) {
return
actionType(_action) == uint8(_type) &&
messageType(_action) == _type;
}
/**
* @notice Checks that the message is of type Transfer
* @param _action The message
* @return True if the message is of type Transfer
*/
function isTransfer(bytes29 _action) internal pure returns (bool) {
return isType(_action, Types.Transfer);
}
/**
* @notice Checks that the message is of type FastTransfer
* @param _action The message
* @return True if the message is of type FastTransfer
*/
function isFastTransfer(bytes29 _action) internal pure returns (bool) {
return isType(_action, Types.FastTransfer);
}
/**
* @notice Formats Transfer
* @param _to The recipient address as bytes32
* @param _amnt The transfer amount
* @param _enableFast True to format FastTransfer, False to format regular Transfer
* @return
*/
function formatTransfer(
bytes32 _to,
uint256 _amnt,
bytes32 _detailsHash,
bool _enableFast
) internal pure returns (bytes29) {
Types _type = _enableFast ? Types.FastTransfer : Types.Transfer;
return
abi.encodePacked(_type, _to, _amnt, _detailsHash).ref(0).castTo(
uint40(_type)
);
}
/**
* @notice Serializes a Token ID struct
* @param _tokenId The token id struct
* @return The formatted Token ID
*/
function formatTokenId(TokenId memory _tokenId)
internal
pure
returns (bytes29)
{
return formatTokenId(_tokenId.domain, _tokenId.id);
}
/**
* @notice Creates a serialized Token ID from components
* @param _domain The domain
* @param _id The ID
* @return The formatted Token ID
*/
function formatTokenId(uint32 _domain, bytes32 _id)
internal
pure
returns (bytes29)
{
return
abi.encodePacked(_domain, _id).ref(0).castTo(uint40(Types.TokenId));
}
/**
* @notice Formats the keccak256 hash of the token details
* Token Details Format:
* length of name cast to bytes - 32 bytes
* name - x bytes (variable)
* length of symbol cast to bytes - 32 bytes
* symbol - x bytes (variable)
* decimals - 1 byte
* @param _name The name
* @param _symbol The symbol
* @param _decimals The decimals
* @return The Details message
*/
function getDetailsHash(
string memory _name,
string memory _symbol,
uint8 _decimals
) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
bytes(_name).length,
_name,
bytes(_symbol).length,
_symbol,
_decimals
)
);
}
/**
* @notice get the preFillId used to identify
* fast liquidity provision for incoming token send messages
* @dev used to identify a token/transfer pair in the prefill LP mapping.
* @param _origin The domain of the chain from which the transfer originated
* @param _nonce The unique identifier for the message from origin to destination
* @param _tokenId The token ID
* @param _action The action
*/
function getPreFillId(
uint32 _origin,
uint32 _nonce,
bytes29 _tokenId,
bytes29 _action
) internal view returns (bytes32) {
bytes29[] memory _views = new bytes29[](3);
_views[0] = abi.encodePacked(_origin, _nonce).ref(0);
_views[1] = _tokenId;
_views[2] = _action;
return TypedMemView.joinKeccak(_views);
}
/**
* @notice Retrieves the domain from a TokenID
* @param _tokenId The message
* @return The domain
*/
function domain(bytes29 _tokenId)
internal
pure
typeAssert(_tokenId, Types.TokenId)
returns (uint32)
{
return uint32(_tokenId.indexUint(0, 4));
}
/**
* @notice Retrieves the ID from a TokenID
* @param _tokenId The message
* @return The ID
*/
function id(bytes29 _tokenId)
internal
pure
typeAssert(_tokenId, Types.TokenId)
returns (bytes32)
{
// before = 4 bytes domain
return _tokenId.index(4, 32);
}
/**
* @notice Retrieves the EVM ID
* @param _tokenId The message
* @return The EVM ID
*/
function evmId(bytes29 _tokenId)
internal
pure
typeAssert(_tokenId, Types.TokenId)
returns (address)
{
// before = 4 bytes domain + 12 bytes empty to trim for address
return _tokenId.indexAddress(16);
}
/**
* @notice Retrieves the action identifier from message
* @param _message The action
* @return The message type
*/
function msgType(bytes29 _message) internal pure returns (uint8) {
return uint8(_message.indexUint(TOKEN_ID_LEN, 1));
}
/**
* @notice Retrieves the identifier from action
* @param _action The action
* @return The action type
*/
function actionType(bytes29 _action) internal pure returns (uint8) {
return uint8(_action.indexUint(0, 1));
}
/**
* @notice Retrieves the recipient from a Transfer
* @param _transferAction The message
* @return The recipient address as bytes32
*/
function recipient(bytes29 _transferAction)
internal
pure
returns (bytes32)
{
// before = 1 byte identifier
return _transferAction.index(1, 32);
}
/**
* @notice Retrieves the EVM Recipient from a Transfer
* @param _transferAction The message
* @return The EVM Recipient
*/
function evmRecipient(bytes29 _transferAction)
internal
pure
returns (address)
{
// before = 1 byte identifier + 12 bytes empty to trim for address = 13 bytes
return _transferAction.indexAddress(13);
}
/**
* @notice Retrieves the amount from a Transfer
* @param _transferAction The message
* @return The amount
*/
function amnt(bytes29 _transferAction) internal pure returns (uint256) {
// before = 1 byte identifier + 32 bytes ID = 33 bytes
return _transferAction.indexUint(33, 32);
}
/**
* @notice Retrieves the detailsHash from a Transfer
* @param _transferAction The message
* @return The detailsHash
*/
function detailsHash(bytes29 _transferAction)
internal
pure
returns (bytes32)
{
// before = 1 byte identifier + 32 bytes ID + 32 bytes amount = 65 bytes
return _transferAction.index(65, 32);
}
/**
* @notice Retrieves the token ID from a Message
* @param _message The message
* @return The ID
*/
function tokenId(bytes29 _message)
internal
pure
typeAssert(_message, Types.Message)
returns (bytes29)
{
return _message.slice(0, TOKEN_ID_LEN, uint40(Types.TokenId));
}
/**
* @notice Retrieves the action data from a Message
* @param _message The message
* @return The action
*/
function action(bytes29 _message)
internal
pure
typeAssert(_message, Types.Message)
returns (bytes29)
{
uint256 _actionLen = _message.len() - TOKEN_ID_LEN;
uint40 _type = uint40(msgType(_message));
return _message.slice(TOKEN_ID_LEN, _actionLen, _type);
}
/**
* @notice Converts to a Message
* @param _message The message
* @return The newly typed message
*/
function tryAsMessage(bytes29 _message) internal pure returns (bytes29) {
if (isValidMessageLength(_message)) {
return _message.castTo(uint40(Types.Message));
}
return TypedMemView.nullView();
}
/**
* @notice Asserts that the message is of type Message
* @param _view The message
* @return The message
*/
function mustBeMessage(bytes29 _view) internal pure returns (bytes29) {
return tryAsMessage(_view).assertValid();
}
}