-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathCalldataDecoder.sol
More file actions
164 lines (147 loc) · 5.37 KB
/
Copy pathCalldataDecoder.sol
File metadata and controls
164 lines (147 loc) · 5.37 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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Library for abi decoding in calldata
library CalldataDecoder {
error SliceOutOfBounds();
/// @notice mask used for offsets and lengths to ensure no overflow
/// @dev no sane abi encoding will pass in an offset or length greater than type(uint32).max
/// (note that this does deviate from standard solidity behavior and offsets/lengths will
/// be interpreted as mod type(uint32).max which will only impact malicious/buggy callers)
uint256 internal constant OFFSET_OR_LENGTH_MASK = 0xffffffff;
uint256 internal constant OFFSET_OR_LENGTH_MASK_AND_WORD_ALIGN = 0xffffffe0;
/// @notice equivalent to SliceOutOfBounds.selector, stored in least-significant bits
uint256 internal constant SLICE_ERROR_SELECTOR = 0x3b99b53d;
function decodeAddress(bytes calldata _bytes) internal pure returns (address value) {
assembly ('memory-safe') {
value := calldataload(_bytes.offset)
}
}
function decodeAddress(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (address value)
{
assembly ('memory-safe') {
value := calldataload(add(_bytes.offset, shl(5, _arg)))
}
}
function decodeUint256(bytes calldata _bytes) internal pure returns (uint256 value) {
assembly ('memory-safe') {
value := calldataload(_bytes.offset)
}
}
function decodeUint256(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (uint256 value)
{
assembly ('memory-safe') {
value := calldataload(add(_bytes.offset, shl(5, _arg)))
}
}
function decodeBool(bytes calldata _bytes) internal pure returns (bool value) {
assembly ('memory-safe') {
value := calldataload(_bytes.offset)
}
}
function decodeBool(bytes calldata _bytes, uint256 _arg) internal pure returns (bool value) {
assembly ('memory-safe') {
value := calldataload(add(_bytes.offset, shl(5, _arg)))
}
}
function decodeBytes32(bytes calldata _bytes) internal pure returns (bytes32 value) {
assembly ('memory-safe') {
value := calldataload(_bytes.offset)
}
}
function decodeBytes32(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (bytes32 value)
{
assembly ('memory-safe') {
value := calldataload(add(_bytes.offset, shl(5, _arg)))
}
}
/// @notice Decode the `_arg`-th element in `_bytes` as a dynamic array
/// @dev The decoding of `length` and `offset` is universal,
/// whereas the type declaration of `res` instructs the compiler how to read it.
/// @param _bytes The input bytes string to slice
/// @param _arg The index of the argument to extract
/// @return length Length of the array
/// @return offset Pointer to the data part of the array
function decodeLengthOffset(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (uint256 length, uint256 offset)
{
assembly ('memory-safe') {
// The offset of the `_arg`-th element is `32 * arg`, which stores the offset of the length pointer.
// shl(5, x) is equivalent to mul(32, x)
let lengthPtr := add(_bytes.offset, calldataload(add(_bytes.offset, shl(5, _arg))))
length := calldataload(lengthPtr)
offset := add(lengthPtr, 0x20)
// if the provided bytes string isnt as long as the encoding says, revert
if lt(add(_bytes.length, _bytes.offset), add(length, offset)) {
mstore(0, SLICE_ERROR_SELECTOR)
revert(0x1c, 4)
}
}
}
/// @notice Decode the `_arg`-th element in `_bytes` as `bytes`
/// @param _bytes The input bytes string to extract a bytes string from
/// @param _arg The index of the argument to extract
function decodeBytes(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (bytes calldata res)
{
(uint256 length, uint256 offset) = decodeLengthOffset(_bytes, _arg);
assembly ('memory-safe') {
res.length := length
res.offset := offset
}
}
/// @notice Decode the `_arg`-th element in `_bytes` as `uint256[]`
/// @param _bytes The input bytes string to extract a uint256 array from
/// @param _arg The index of the argument to extract
function decodeUint256Array(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (uint256[] calldata res)
{
(uint256 length, uint256 offset) = decodeLengthOffset(_bytes, _arg);
assembly ('memory-safe') {
res.length := length
res.offset := offset
}
}
/// @notice Decode the `_arg`-th element in `_bytes` as `address[]`
/// @param _bytes The input bytes string to extract an address array from
/// @param _arg The index of the argument to extract
function decodeAddressArray(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (address[] calldata res)
{
(uint256 length, uint256 offset) = decodeLengthOffset(_bytes, _arg);
assembly ('memory-safe') {
res.length := length
res.offset := offset
}
}
/// @notice Decode the `_arg`-th element in `_bytes` as `bytes32[]`
/// @param _bytes The input bytes string to extract a bytes32 array from
/// @param _arg The index of the argument to extract
function decodeBytes32Array(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (bytes32[] calldata res)
{
(uint256 length, uint256 offset) = decodeLengthOffset(_bytes, _arg);
assembly ('memory-safe') {
res.length := length
res.offset := offset
}
}
}