Skip to content

Commit 29b7129

Browse files
committed
Merge branch 'master' into msg-sender-trick
2 parents 8d8c13d + 0570e16 commit 29b7129

File tree

13 files changed

+363
-135
lines changed

13 files changed

+363
-135
lines changed

contracts/factory/Factory.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ library Factory {
4646
}
4747

4848
/**
49-
* @notice calculate the _deployMetamorphicContract deployment address for a given salt
49+
* @notice calculate the deployment address for a given salt
5050
* @param initCodeHash hash of contract initialization code
5151
* @param salt input for deterministic address calculation
5252
* @return deployment address

contracts/proxy/IProxy.sol

-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,5 @@ pragma solidity ^0.8.20;
55
import { _IProxy } from './_IProxy.sol';
66

77
interface IProxy is _IProxy {
8-
error Proxy__ImplementationIsNotContract();
9-
108
fallback() external payable;
119
}

contracts/proxy/Proxy.sol

+3-31
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,18 @@
22

33
pragma solidity ^0.8.20;
44

5-
import { AddressUtils } from '../utils/AddressUtils.sol';
65
import { IProxy } from './IProxy.sol';
76
import { _Proxy } from './_Proxy.sol';
87

98
/**
109
* @title Base proxy contract
1110
*/
1211
abstract contract Proxy is IProxy, _Proxy {
13-
using AddressUtils for address;
14-
1512
/**
1613
* @notice delegate all calls to implementation contract
17-
* @dev reverts if implementation address contains no code, for compatibility with metamorphic contracts
18-
* @dev memory location in use by assembly may be unsafe in other contexts
14+
* @dev reverts if implementation address contains no code
1915
*/
20-
fallback() external payable virtual {
21-
address implementation = _getImplementation();
22-
23-
if (!implementation.isContract())
24-
revert Proxy__ImplementationIsNotContract();
25-
26-
assembly {
27-
calldatacopy(0, 0, calldatasize())
28-
let result := delegatecall(
29-
gas(),
30-
implementation,
31-
0,
32-
calldatasize(),
33-
0,
34-
0
35-
)
36-
returndatacopy(0, 0, returndatasize())
37-
38-
switch result
39-
case 0 {
40-
revert(0, returndatasize())
41-
}
42-
default {
43-
return(0, returndatasize())
44-
}
45-
}
16+
fallback() external payable {
17+
_fallback();
4618
}
4719
}

contracts/proxy/_IProxy.sol

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22

33
pragma solidity ^0.8.20;
44

5-
interface _IProxy {}
5+
interface _IProxy {
6+
error Proxy__ImplementationIsNotContract();
7+
}

contracts/proxy/_Proxy.sol

+41-8
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,9 @@ abstract contract _Proxy is _IProxy {
1616
virtual
1717
returns (address implementation)
1818
{
19-
// inline storage layout retrieval uses less gas
20-
ProxyStorage.Layout storage $;
21-
bytes32 slot = ProxyStorage.DEFAULT_STORAGE_SLOT;
22-
assembly {
23-
$.slot := slot
24-
}
25-
26-
implementation = $.implementation;
19+
implementation = ProxyStorage
20+
.layout(ProxyStorage.DEFAULT_STORAGE_SLOT)
21+
.implementation;
2722
}
2823

2924
/**
@@ -35,4 +30,42 @@ abstract contract _Proxy is _IProxy {
3530
.layout(ProxyStorage.DEFAULT_STORAGE_SLOT)
3631
.implementation = implementation;
3732
}
33+
34+
/**
35+
* @notice delegate all calls to implementation contract
36+
* @dev memory location in use by assembly may be unsafe in other contexts
37+
* @dev function declares no return value, but data is returned via assembly
38+
*/
39+
function _fallback() internal virtual {
40+
address implementation = _getImplementation();
41+
42+
assembly {
43+
calldatacopy(0, 0, calldatasize())
44+
45+
let result := delegatecall(
46+
gas(),
47+
implementation,
48+
0,
49+
calldatasize(),
50+
0,
51+
0
52+
)
53+
54+
returndatacopy(0, 0, returndatasize())
55+
56+
if iszero(result) {
57+
revert(0, returndatasize())
58+
}
59+
60+
if returndatasize() {
61+
return(0, returndatasize())
62+
}
63+
64+
if extcodesize(implementation) {
65+
return(0, returndatasize())
66+
}
67+
}
68+
69+
revert Proxy__ImplementationIsNotContract();
70+
}
3871
}

contracts/proxy/diamond/_DiamondProxy.sol

+17-7
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,24 @@ abstract contract _DiamondProxy is _IDiamondProxy, _Proxy {
2525
override
2626
returns (address implementation)
2727
{
28-
// inline storage layout retrieval uses less gas
29-
ERC2535Storage.Layout storage $;
30-
bytes32 slot = ERC2535Storage.DEFAULT_STORAGE_SLOT;
31-
assembly {
32-
$.slot := slot
33-
}
28+
implementation = _facetAddress(msg.sig);
29+
}
3430

35-
implementation = address(bytes20($.selectorInfo[msg.sig]));
31+
/**
32+
* @notice get the address of the facet associated with given selector
33+
* @param selector function selector to query
34+
* @return facet facet address (zero address if not found)
35+
*/
36+
function _facetAddress(
37+
bytes4 selector
38+
) internal view returns (address facet) {
39+
facet = address(
40+
bytes20(
41+
ERC2535Storage
42+
.layout(ERC2535Storage.DEFAULT_STORAGE_SLOT)
43+
.selectorInfo[selector]
44+
)
45+
);
3646
}
3747

3848
/**

contracts/proxy/diamond/readable/_DiamondProxyReadable.sol

-17
Original file line numberDiff line numberDiff line change
@@ -200,21 +200,4 @@ abstract contract _DiamondProxyReadable is
200200
mstore(addresses, numFacets)
201201
}
202202
}
203-
204-
/**
205-
* @notice get the address of the facet associated with given selector
206-
* @param selector function selector to query
207-
* @return facet facet address (zero address if not found)
208-
*/
209-
function _facetAddress(
210-
bytes4 selector
211-
) internal view returns (address facet) {
212-
facet = address(
213-
bytes20(
214-
ERC2535Storage
215-
.layout(ERC2535Storage.DEFAULT_STORAGE_SLOT)
216-
.selectorInfo[selector]
217-
)
218-
);
219-
}
220203
}

contracts/token/non_fungible/_NonFungibleToken.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ abstract contract _NonFungibleToken is
245245
tokenId,
246246
data
247247
),
248-
'NonFungibleToken: transfer to non ERC721Receiver implementer'
248+
NonFungibleToken__ERC721ReceiverNotImplemented.selector
249249
);
250250

251251
bytes4 returnValue = abi.decode(returnData, (bytes4));

contracts/utils/AddressUtils.sol

+54-16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ library AddressUtils {
1010
error AddressUtils__InsufficientBalance();
1111
error AddressUtils__NotContract();
1212
error AddressUtils__SendValueFailed();
13+
error AddressUtils__FailedCall();
14+
error AddressUtils__FailedCallWithValue();
15+
error AddressUtils__FailedDelegatecall();
1316

1417
function toString(address account) internal pure returns (string memory) {
1518
return uint256(uint160(account)).toHexString(20);
@@ -32,14 +35,13 @@ library AddressUtils {
3235
address target,
3336
bytes memory data
3437
) internal returns (bytes memory) {
35-
return
36-
functionCall(target, data, 'AddressUtils: failed low-level call');
38+
return functionCall(target, data, AddressUtils__FailedCall.selector);
3739
}
3840

3941
function functionCall(
4042
address target,
4143
bytes memory data,
42-
string memory error
44+
bytes4 error
4345
) internal returns (bytes memory) {
4446
return _functionCallWithValue(target, data, 0, error);
4547
}
@@ -54,21 +56,43 @@ library AddressUtils {
5456
target,
5557
data,
5658
value,
57-
'AddressUtils: failed low-level call with value'
59+
AddressUtils__FailedCallWithValue.selector
5860
);
5961
}
6062

6163
function functionCallWithValue(
6264
address target,
6365
bytes memory data,
6466
uint256 value,
65-
string memory error
67+
bytes4 error
6668
) internal returns (bytes memory) {
6769
if (value > address(this).balance)
6870
revert AddressUtils__InsufficientBalance();
6971
return _functionCallWithValue(target, data, value, error);
7072
}
7173

74+
function functionDelegateCall(
75+
address target,
76+
bytes memory data
77+
) internal returns (bytes memory) {
78+
return
79+
functionDelegateCall(
80+
target,
81+
data,
82+
AddressUtils__FailedDelegatecall.selector
83+
);
84+
}
85+
86+
function functionDelegateCall(
87+
address target,
88+
bytes memory data,
89+
bytes4 error
90+
) internal returns (bytes memory) {
91+
(bool success, bytes memory returnData) = target.delegatecall(data);
92+
_verifyCallResultFromTarget(target, success, returnData, error);
93+
return returnData;
94+
}
95+
7296
/**
7397
* @notice execute arbitrary external call with limited gas usage and amount of copied return data
7498
* @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License)
@@ -120,23 +144,37 @@ library AddressUtils {
120144
address target,
121145
bytes memory data,
122146
uint256 value,
123-
string memory error
147+
bytes4 error
124148
) private returns (bytes memory) {
125-
if (!isContract(target)) revert AddressUtils__NotContract();
126-
127149
(bool success, bytes memory returnData) = target.call{ value: value }(
128150
data
129151
);
152+
_verifyCallResultFromTarget(target, success, returnData, error);
153+
return returnData;
154+
}
130155

131-
if (success) {
132-
return returnData;
133-
} else if (returnData.length > 0) {
134-
assembly {
135-
let returnData_size := mload(returnData)
136-
revert(add(32, returnData), returnData_size)
156+
function _verifyCallResultFromTarget(
157+
address target,
158+
bool success,
159+
bytes memory returnData,
160+
bytes4 error
161+
) private view {
162+
if (!success) {
163+
if (returnData.length == 0) {
164+
assembly {
165+
mstore(0, error)
166+
revert(0, 4)
167+
}
168+
} else {
169+
assembly {
170+
let returnData_size := mload(returnData)
171+
revert(add(32, returnData), returnData_size)
172+
}
137173
}
138-
} else {
139-
revert(error);
140174
}
175+
176+
// code check is only required if call is successful and without return data
177+
if (returnData.length == 0 && !isContract(target))
178+
revert AddressUtils__NotContract();
141179
}
142180
}

contracts/utils/SafeERC20.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ library SafeERC20 {
9191
function _callOptionalReturn(IERC20 token, bytes memory data) private {
9292
bytes memory returndata = address(token).functionCall(
9393
data,
94-
'SafeERC20: low-level call failed'
94+
SafeERC20__OperationFailed.selector
9595
);
9696

9797
if (returndata.length > 0) {

spec/token/non_fungible/NonFungibleToken.behavior.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,9 @@ export function describeBehaviorOfNonFungibleToken(
378378
[
379379
'safeTransferFrom(address,address,uint256)'
380380
](holder.address, await instance.getAddress(), tokenId),
381-
).to.be.revertedWith(
382-
'NonFungibleToken: transfer to non ERC721Receiver implementer',
381+
).to.be.revertedWithCustomError(
382+
instance,
383+
'NonFungibleToken__ERC721ReceiverNotImplemented',
383384
);
384385
});
385386

@@ -510,8 +511,9 @@ export function describeBehaviorOfNonFungibleToken(
510511
[
511512
'safeTransferFrom(address,address,uint256,bytes)'
512513
](holder.address, await instance.getAddress(), tokenId, '0x'),
513-
).to.be.revertedWith(
514-
'NonFungibleToken: transfer to non ERC721Receiver implementer',
514+
).to.be.revertedWithCustomError(
515+
instance,
516+
'NonFungibleToken__ERC721ReceiverNotImplemented',
515517
);
516518
});
517519

0 commit comments

Comments
 (0)