Skip to content

Commit 756a119

Browse files
committed
Implement branching for safe 1271 callers and fallback for personal sign
1 parent 17f02c3 commit 756a119

11 files changed

+182
-39
lines changed

snapshots/ERC7914Test.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"approveNative": "45972",
33
"approveNativeTransient": "24024",
4-
"transferFromNative": "31956"
4+
"transferFromNative": "31978"
55
}
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"hanldeOps_BATCHED_CALL_singleCall_P256": "209155",
3-
"hanldeOps_BATCHED_CALL_singleCall_eoaSigner": "184181"
2+
"hanldeOps_BATCHED_CALL_singleCall_P256": "209177",
3+
"hanldeOps_BATCHED_CALL_singleCall_eoaSigner": "184203"
44
}
+11-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
2-
"execute_BATCHED_CALL_SUPPORTS_OPDATA_singleCall": "92954",
3-
"execute_BATCHED_CALL_SUPPORTS_OPDATA_twoCalls": "129562",
4-
"execute_BATCHED_CALL_opData_P256_singleCall": "118266",
5-
"execute_BATCHED_CALL_opData_singleCall": "92954",
6-
"execute_BATCHED_CALL_opData_singleCall_native": "93784",
7-
"execute_BATCHED_CALL_opData_twoCalls": "129562",
8-
"execute_BATCHED_CALL_singleCall": "59600",
9-
"execute_BATCHED_CALL_singleCall_native": "59679",
10-
"execute_BATCHED_CALL_twoCalls": "95394",
11-
"execute_invalidMode_reverts": "22997",
12-
"multicall": "178476"
2+
"execute_BATCHED_CALL_SUPPORTS_OPDATA_singleCall": "92976",
3+
"execute_BATCHED_CALL_SUPPORTS_OPDATA_twoCalls": "129584",
4+
"execute_BATCHED_CALL_opData_P256_singleCall": "118288",
5+
"execute_BATCHED_CALL_opData_singleCall": "92976",
6+
"execute_BATCHED_CALL_opData_singleCall_native": "93806",
7+
"execute_BATCHED_CALL_opData_twoCalls": "129584",
8+
"execute_BATCHED_CALL_singleCall": "59622",
9+
"execute_BATCHED_CALL_singleCall_native": "59701",
10+
"execute_BATCHED_CALL_twoCalls": "95416",
11+
"execute_invalidMode_reverts": "23019",
12+
"multicall": "178542"
1313
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
{
22
"isValidSignature_P256": "41828",
3+
"isValidSignature_P256_personalSign": "33738",
4+
"isValidSignature_P256_personalSign_notNested_usingHashTypedData": "306194",
5+
"isValidSignature_P256_typedData_notNested_safeERC1271Caller": "32853",
36
"isValidSignature_P256_withHook": "47986",
47
"isValidSignature_WebAuthnP256": "48515",
5-
"isValidSignature_personalSign_P256Key": "13429",
6-
"isValidSignature_personalSign_rootKey": "6992",
7-
"isValidSignature_rootKey": "17370"
8+
"isValidSignature_rootKey": "17370",
9+
"isValidSignature_rootKey_personalSign": "9301",
10+
"isValidSignature_rootKey_personalSign_notNested_usingHashTypedData": "13708",
11+
"isValidSignature_rootKey_typedData_notNested_safeERC1271Caller": "8416"
812
}

snapshots/MinimalDelegationTest.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"minimalDelegationEntry bytecode size": "20673",
2+
"minimalDelegationEntry bytecode size": "20946",
33
"register": "184758",
4-
"revoke": "54543",
4+
"revoke": "54560",
55
"validateUserOp_missingAccountFunds": "64567",
66
"validateUserOp_no_missingAccountFunds": "33929"
77
}

snapshots/NonceManagerTest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"invalidateNonce": "45356"
2+
"invalidateNonce": "45378"
33
}

src/ERC1271.sol

+16-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,29 @@
22
pragma solidity ^0.8.23;
33

44
import {IERC1271} from "./interfaces/IERC1271.sol";
5+
import {BaseAuthorization} from "./BaseAuthorization.sol";
56

67
/// @title ERC-1271
7-
/// @notice Abstract ERC1271 implementation
8-
abstract contract ERC1271 is IERC1271 {
8+
/// @notice Abstract ERC1271 implementation which supports nested EIP-712 workflows as defined by ERC-7739
9+
abstract contract ERC1271 is IERC1271, BaseAuthorization {
10+
mapping(address => bool) private _erc1271CallerIsSafe;
11+
912
/// @dev The magic value returned by `isValidSignature()` if the signature is valid.
1013
bytes4 internal constant _1271_MAGIC_VALUE = 0x1626ba7e;
1114
/// @dev The magic value returned by `isValidSignature()` if the signature is invalid.
1215
bytes4 internal constant _1271_INVALID_VALUE = 0xffffffff;
1316

17+
/// @dev Returns whether the caller is considered safe, such
18+
/// that we don't need to use the nested EIP-712 workflow as defined by ERC-7739
19+
function _isSafeERC1271Caller(address caller) internal view virtual returns (bool) {
20+
return _erc1271CallerIsSafe[caller];
21+
}
22+
23+
/// @dev Sets whether the caller is considered safe to skip the nested EIP-712 workflow
24+
function setERC1271CallerIsSafe(address caller, bool isSafe) external onlyThis {
25+
_erc1271CallerIsSafe[caller] = isSafe;
26+
}
27+
1428
/// @inheritdoc IERC1271
1529
function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4);
1630
}

src/MinimalDelegation.sol

+13-3
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,21 @@ contract MinimalDelegation is
197197

198198
Key memory key = getKey(keyHash);
199199

200-
// Must be branched because we do abi decoding in memory which will throw since the ecnoding schemes are different
201-
// Early check for personal signature which must be length 64 or 65 (k1 or r1 curve)
202200
bool isValid;
201+
// Must be branched because we do abi decoding in memory which will throw since the encoding schemes are different
202+
// ECDSA signatures are 65 bytes while P256 signatures are 64 bytes
203203
if (signature.length == 64 || signature.length == 65) {
204-
isValid = _isValidNestedPersonalSignature(key, data, signature);
204+
if(_isSafeERC1271Caller(msg.sender)) {
205+
// If the caller is safe we can simply verify the key's signature over `data`
206+
// Data is already hashed with the app's domain separator so we don't rehash
207+
isValid = key.verify(data, signature);
208+
} else {
209+
// Otherwise, we try to verify the signature using NestedPersonalSign
210+
// falling back to regular PersonalSign
211+
isValid =
212+
_isValidNestedPersonalSignature(key, data, signature)
213+
|| key.verify(hashTypedData(data), signature);
214+
}
205215
} else {
206216
isValid = _isValidTypedDataSig(key, data, signature);
207217
}

src/interfaces/IERC1271.sol

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ pragma solidity ^0.8.0;
33

44
/// @title IERC1271
55
interface IERC1271 {
6+
/// @notice Sets whether the caller is considered safe to skip the nested EIP-712 workflow
7+
function setERC1271CallerIsSafe(address caller, bool isSafe) external;
8+
69
/// @notice Validates the `signature` against the given `hash`.
710
/// @dev Wraps the given `hash` in a EIP-712 compliant struct along with the domain separator to be replay safe. Then validates the signature against it.
811
/// @return result `0x1626ba7e` if validation succeeded, else `0xffffffff`.

0 commit comments

Comments
 (0)