@1inch/solidity-utils 2.0.24 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.0;
|
|
4
|
+
pragma abicoder v1;
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
interface IERC20MetadataUppercase {
|
|
8
|
+
function NAME() external view returns (string memory); // solhint-disable-line func-name-mixedcase
|
|
9
|
+
function SYMBOL() external view returns (string memory); // solhint-disable-line func-name-mixedcase
|
|
10
|
+
}
|
|
@@ -16,6 +16,8 @@ library ECDSA {
|
|
|
16
16
|
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
|
|
17
17
|
// these malleable signatures as well.
|
|
18
18
|
uint256 private constant _S_BOUNDARY = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 + 1;
|
|
19
|
+
uint256 private constant _COMPACT_S_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
|
|
20
|
+
uint256 private constant _COMPACT_V_SHIFT = 255;
|
|
19
21
|
|
|
20
22
|
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns(address signer) {
|
|
21
23
|
/// @solidity memory-safe-assembly
|
|
@@ -37,12 +39,12 @@ library ECDSA {
|
|
|
37
39
|
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns(address signer) {
|
|
38
40
|
/// @solidity memory-safe-assembly
|
|
39
41
|
assembly { // solhint-disable-line no-inline-assembly
|
|
40
|
-
let s :=
|
|
42
|
+
let s := and(vs, _COMPACT_S_MASK)
|
|
41
43
|
if lt(s, _S_BOUNDARY) {
|
|
42
44
|
let ptr := mload(0x40)
|
|
43
45
|
|
|
44
46
|
mstore(ptr, hash)
|
|
45
|
-
mstore(add(ptr, 0x20), add(27, shr(
|
|
47
|
+
mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs)))
|
|
46
48
|
mstore(add(ptr, 0x40), r)
|
|
47
49
|
mstore(add(ptr, 0x60), s)
|
|
48
50
|
mstore(0, 0)
|
|
@@ -52,30 +54,20 @@ library ECDSA {
|
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
/// @dev only compact signatures are supported see EIP-2098
|
|
55
58
|
function recover(bytes32 hash, bytes calldata signature) internal view returns(address signer) {
|
|
56
59
|
/// @solidity memory-safe-assembly
|
|
57
60
|
assembly { // solhint-disable-line no-inline-assembly
|
|
58
|
-
let ptr := mload(0x40)
|
|
59
|
-
|
|
60
61
|
// memory[ptr:ptr+0x80] = (hash, v, r, s)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
mstore(add(ptr, 0x20), byte(0, calldataload(add(signature.offset, 0x40))))
|
|
65
|
-
calldatacopy(add(ptr, 0x40), signature.offset, 0x40)
|
|
66
|
-
}
|
|
67
|
-
case 64 {
|
|
62
|
+
if eq(signature.length, 64) {
|
|
63
|
+
let ptr := mload(0x40)
|
|
64
|
+
|
|
68
65
|
// memory[ptr+0x20:ptr+0x80] = (v, r, s)
|
|
69
66
|
let vs := calldataload(add(signature.offset, 0x20))
|
|
70
|
-
mstore(add(ptr, 0x20), add(27, shr(
|
|
67
|
+
mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs)))
|
|
71
68
|
calldatacopy(add(ptr, 0x40), signature.offset, 0x20)
|
|
72
|
-
mstore(add(ptr, 0x60),
|
|
73
|
-
}
|
|
74
|
-
default {
|
|
75
|
-
ptr := 0
|
|
76
|
-
}
|
|
69
|
+
mstore(add(ptr, 0x60), and(vs, _COMPACT_S_MASK))
|
|
77
70
|
|
|
78
|
-
if ptr {
|
|
79
71
|
if lt(mload(add(ptr, 0x60)), _S_BOUNDARY) {
|
|
80
72
|
// memory[ptr:ptr+0x20] = (hash)
|
|
81
73
|
mstore(ptr, hash)
|
|
@@ -90,7 +82,7 @@ library ECDSA {
|
|
|
90
82
|
|
|
91
83
|
function recoverOrIsValidSignature(address signer, bytes32 hash, bytes calldata signature) internal view returns(bool success) {
|
|
92
84
|
if (signer == address(0)) return false;
|
|
93
|
-
if (
|
|
85
|
+
if (signature.length == 64 && recover(hash, signature) == signer) {
|
|
94
86
|
return true;
|
|
95
87
|
}
|
|
96
88
|
return isValidSignature(signer, hash, signature);
|
|
@@ -133,9 +125,8 @@ library ECDSA {
|
|
|
133
125
|
mstore(add(ptr, 0x24), 0x40)
|
|
134
126
|
mstore(add(ptr, 0x44), signature.length)
|
|
135
127
|
calldatacopy(add(ptr, 0x64), signature.offset, signature.length)
|
|
136
|
-
mstore(0, 0)
|
|
137
128
|
if staticcall(gas(), signer, ptr, add(0x64, signature.length), 0, 0x20) {
|
|
138
|
-
success := eq(selector, mload(0))
|
|
129
|
+
success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
|
|
139
130
|
}
|
|
140
131
|
}
|
|
141
132
|
}
|
|
@@ -153,9 +144,8 @@ library ECDSA {
|
|
|
153
144
|
mstore(add(ptr, 0x64), r)
|
|
154
145
|
mstore(add(ptr, 0x84), s)
|
|
155
146
|
mstore8(add(ptr, 0xa4), v)
|
|
156
|
-
mstore(0, 0)
|
|
157
147
|
if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) {
|
|
158
|
-
success := eq(selector, mload(0))
|
|
148
|
+
success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
|
|
159
149
|
}
|
|
160
150
|
}
|
|
161
151
|
}
|
|
@@ -174,9 +164,8 @@ library ECDSA {
|
|
|
174
164
|
mstore(add(ptr, 0x44), 64)
|
|
175
165
|
mstore(add(ptr, 0x64), r)
|
|
176
166
|
mstore(add(ptr, 0x84), vs)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
success := eq(selector, mload(0))
|
|
167
|
+
if staticcall(gas(), signer, ptr, 0xa4, 0, 0x20) {
|
|
168
|
+
success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
|
|
180
169
|
}
|
|
181
170
|
}
|
|
182
171
|
}
|
|
@@ -194,11 +183,10 @@ library ECDSA {
|
|
|
194
183
|
mstore(add(ptr, 0x24), 0x40)
|
|
195
184
|
mstore(add(ptr, 0x44), 65)
|
|
196
185
|
mstore(add(ptr, 0x64), r)
|
|
197
|
-
mstore(add(ptr, 0x84),
|
|
198
|
-
mstore8(add(ptr, 0xa4), add(27, shr(
|
|
199
|
-
mstore(0, 0)
|
|
186
|
+
mstore(add(ptr, 0x84), and(vs, _COMPACT_S_MASK))
|
|
187
|
+
mstore8(add(ptr, 0xa4), add(27, shr(_COMPACT_V_SHIFT, vs)))
|
|
200
188
|
if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) {
|
|
201
|
-
success := eq(selector, mload(0))
|
|
189
|
+
success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
|
|
202
190
|
}
|
|
203
191
|
}
|
|
204
192
|
}
|
|
@@ -51,12 +51,12 @@ library StringUtil {
|
|
|
51
51
|
|
|
52
52
|
result := mload(0x40)
|
|
53
53
|
let length := mload(data)
|
|
54
|
-
let resultLength :=
|
|
55
|
-
let toPtr := add(result,
|
|
54
|
+
let resultLength := shl(1, length)
|
|
55
|
+
let toPtr := add(result, 0x22) // 32 bytes for length + 2 bytes for '0x'
|
|
56
56
|
mstore(0x40, add(toPtr, resultLength)) // move free memory pointer
|
|
57
|
-
mstore(result,
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
mstore(add(result, 2), 0x3078) // 0x3078 is right aligned so we write to `result + 2`
|
|
58
|
+
// to store the last 2 bytes in the beginning of the string
|
|
59
|
+
mstore(result, add(resultLength, 2)) // extra 2 bytes for '0x'
|
|
60
60
|
|
|
61
61
|
for {
|
|
62
62
|
let fromPtr := add(data, 0x20)
|
|
@@ -5,24 +5,21 @@ pragma abicoder v1;
|
|
|
5
5
|
|
|
6
6
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
7
7
|
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
8
|
+
import "../interfaces/IERC20MetadataUppercase.sol";
|
|
8
9
|
import "./SafeERC20.sol";
|
|
9
10
|
import "./StringUtil.sol";
|
|
10
11
|
|
|
11
|
-
interface IERC20MetadataUppercase {
|
|
12
|
-
function NAME() external view returns (string memory); // solhint-disable-line func-name-mixedcase
|
|
13
|
-
function SYMBOL() external view returns (string memory); // solhint-disable-line func-name-mixedcase
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
library UniERC20 {
|
|
17
13
|
using SafeERC20 for IERC20;
|
|
18
14
|
|
|
19
15
|
error InsufficientBalance();
|
|
20
|
-
error ETHSendFailed();
|
|
21
16
|
error ApproveCalledOnETH();
|
|
22
17
|
error NotEnoughValue();
|
|
23
18
|
error FromIsNotSender();
|
|
24
19
|
error ToIsNotThis();
|
|
20
|
+
error ETHTransferFailed();
|
|
25
21
|
|
|
22
|
+
uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
|
|
26
23
|
IERC20 private constant _ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
|
|
27
24
|
IERC20 private constant _ZERO_ADDRESS = IERC20(address(0));
|
|
28
25
|
|
|
@@ -38,18 +35,21 @@ library UniERC20 {
|
|
|
38
35
|
}
|
|
39
36
|
}
|
|
40
37
|
|
|
38
|
+
/// @dev note that this function does nothing in case of zero amount
|
|
41
39
|
function uniTransfer(IERC20 token, address payable to, uint256 amount) internal {
|
|
42
40
|
if (amount > 0) {
|
|
43
41
|
if (isETH(token)) {
|
|
44
42
|
if (address(this).balance < amount) revert InsufficientBalance();
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
// solhint-disable-next-line avoid-low-level-calls
|
|
44
|
+
(bool success, ) = to.call{value: amount, gas: _RAW_CALL_GAS_LIMIT}("");
|
|
45
|
+
if (!success) revert ETHTransferFailed();
|
|
47
46
|
} else {
|
|
48
47
|
token.safeTransfer(to, amount);
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
|
|
52
|
+
/// @dev note that this function does nothing in case of zero amount
|
|
53
53
|
function uniTransferFrom(IERC20 token, address payable from, address to, uint256 amount) internal {
|
|
54
54
|
if (amount > 0) {
|
|
55
55
|
if (isETH(token)) {
|
|
@@ -59,8 +59,9 @@ library UniERC20 {
|
|
|
59
59
|
if (msg.value > amount) {
|
|
60
60
|
// Return remainder if exist
|
|
61
61
|
unchecked {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// solhint-disable-next-line avoid-low-level-calls
|
|
63
|
+
(bool success, ) = from.call{value: msg.value - amount, gas: _RAW_CALL_GAS_LIMIT}("");
|
|
64
|
+
if (!success) revert ETHTransferFailed();
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
} else {
|
|
@@ -83,7 +84,9 @@ library UniERC20 {
|
|
|
83
84
|
token.forceApprove(to, amount);
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
|
|
87
|
+
/// 20K gas is provided to account for possible implementations of name/symbol
|
|
88
|
+
/// (token implementation might be behind proxy or store the value in storage)
|
|
89
|
+
function _uniDecode(IERC20 token, bytes4 lowerCaseSelector, bytes4 upperCaseSelector) private view returns(string memory result) {
|
|
87
90
|
if (isETH(token)) {
|
|
88
91
|
return "ETH";
|
|
89
92
|
}
|
|
@@ -97,10 +100,14 @@ library UniERC20 {
|
|
|
97
100
|
);
|
|
98
101
|
}
|
|
99
102
|
|
|
100
|
-
if (success && data.length >=
|
|
103
|
+
if (success && data.length >= 0x40) {
|
|
101
104
|
(uint256 offset, uint256 len) = abi.decode(data, (uint256, uint256));
|
|
102
|
-
if (offset == 0x20 && len > 0 &&
|
|
103
|
-
|
|
105
|
+
if (offset == 0x20 && len > 0 && data.length == 0x40 + len) {
|
|
106
|
+
/// @solidity memory-safe-assembly
|
|
107
|
+
assembly { // solhint-disable-line no-inline-assembly
|
|
108
|
+
result := add(data, 0x20)
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
|
|
@@ -113,6 +120,7 @@ library UniERC20 {
|
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
if (len > 0) {
|
|
123
|
+
/// @solidity memory-safe-assembly
|
|
116
124
|
assembly { // solhint-disable-line no-inline-assembly
|
|
117
125
|
mstore(data, len)
|
|
118
126
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.0;
|
|
4
|
+
|
|
5
|
+
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
|
|
6
|
+
|
|
7
|
+
contract ERC20PermitMock is ERC20Permit {
|
|
8
|
+
constructor(
|
|
9
|
+
string memory name,
|
|
10
|
+
string memory symbol,
|
|
11
|
+
address initialAccount,
|
|
12
|
+
uint256 initialBalance
|
|
13
|
+
) payable ERC20(name, symbol) ERC20Permit(name) {
|
|
14
|
+
_mint(initialAccount, initialBalance);
|
|
15
|
+
}
|
|
16
|
+
}
|