@1inch/solidity-utils 2.0.25 → 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 := shr(1, shl(1, vs))
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(255, vs)))
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
- switch signature.length
62
- case 65 {
63
- // memory[ptr+0x20:ptr+0x80] = (v, r, s)
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(255, vs)))
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), shr(1, shl(1, vs)))
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 ((signature.length == 64 || signature.length == 65) && recover(hash, signature) == signer) {
85
+ if (signature.length == 64 && recover(hash, signature) == signer) {
94
86
  return true;
95
87
  }
96
88
  return isValidSignature(signer, hash, signature);
@@ -172,7 +164,7 @@ library ECDSA {
172
164
  mstore(add(ptr, 0x44), 64)
173
165
  mstore(add(ptr, 0x64), r)
174
166
  mstore(add(ptr, 0x84), vs)
175
- if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) {
167
+ if staticcall(gas(), signer, ptr, 0xa4, 0, 0x20) {
176
168
  success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
177
169
  }
178
170
  }
@@ -191,8 +183,8 @@ library ECDSA {
191
183
  mstore(add(ptr, 0x24), 0x40)
192
184
  mstore(add(ptr, 0x44), 65)
193
185
  mstore(add(ptr, 0x64), r)
194
- mstore(add(ptr, 0x84), shr(1, shl(1, vs)))
195
- mstore8(add(ptr, 0xa4), add(27, shr(255, vs)))
186
+ mstore(add(ptr, 0x84), and(vs, _COMPACT_S_MASK))
187
+ mstore8(add(ptr, 0xa4), add(27, shr(_COMPACT_V_SHIFT, vs)))
196
188
  if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) {
197
189
  success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
198
190
  }
@@ -5,14 +5,10 @@ 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
 
@@ -21,7 +17,9 @@ library UniERC20 {
21
17
  error NotEnoughValue();
22
18
  error FromIsNotSender();
23
19
  error ToIsNotThis();
20
+ error ETHTransferFailed();
24
21
 
22
+ uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
25
23
  IERC20 private constant _ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
26
24
  IERC20 private constant _ZERO_ADDRESS = IERC20(address(0));
27
25
 
@@ -37,18 +35,21 @@ library UniERC20 {
37
35
  }
38
36
  }
39
37
 
38
+ /// @dev note that this function does nothing in case of zero amount
40
39
  function uniTransfer(IERC20 token, address payable to, uint256 amount) internal {
41
40
  if (amount > 0) {
42
41
  if (isETH(token)) {
43
42
  if (address(this).balance < amount) revert InsufficientBalance();
44
- // we do not use low-level calls to protect from possible reentrancy
45
- to.transfer(amount);
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();
46
46
  } else {
47
47
  token.safeTransfer(to, amount);
48
48
  }
49
49
  }
50
50
  }
51
51
 
52
+ /// @dev note that this function does nothing in case of zero amount
52
53
  function uniTransferFrom(IERC20 token, address payable from, address to, uint256 amount) internal {
53
54
  if (amount > 0) {
54
55
  if (isETH(token)) {
@@ -57,8 +58,11 @@ library UniERC20 {
57
58
  if (to != address(this)) revert ToIsNotThis();
58
59
  if (msg.value > amount) {
59
60
  // Return remainder if exist
60
- // we do not use low-level calls to protect from possible reentrancy
61
- unchecked { from.transfer(msg.value - amount); }
61
+ unchecked {
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();
65
+ }
62
66
  }
63
67
  } else {
64
68
  token.safeTransferFrom(from, to, amount);
@@ -80,6 +84,8 @@ library UniERC20 {
80
84
  token.forceApprove(to, amount);
81
85
  }
82
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)
83
89
  function _uniDecode(IERC20 token, bytes4 lowerCaseSelector, bytes4 upperCaseSelector) private view returns(string memory result) {
84
90
  if (isETH(token)) {
85
91
  return "ETH";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1inch/solidity-utils",
3
- "version": "2.0.25",
3
+ "version": "2.1.0",
4
4
  "main": "dist/src/index.js",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {