Skip to content

Commit 630ba44

Browse files
Amxxernestognwarr00
authored
Audit fixes for v5.3 (#99)
Co-authored-by: Ernesto García <[email protected]> Co-authored-by: Arr00 <[email protected]>
1 parent e2e4556 commit 630ba44

File tree

14 files changed

+124
-89
lines changed

14 files changed

+124
-89
lines changed

contracts/account/extensions/AccountERC7579.sol

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.24;
3+
pragma solidity ^0.8.27;
44

55
import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";
66
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
@@ -19,7 +19,7 @@ import {Account} from "../Account.sol";
1919
* To comply with the ERC-1271 support requirement, this contract defers signature validation to
2020
* installed validator modules by calling {IERC7579Validator-isValidSignatureWithSender}.
2121
*
22-
* This contract does not implement validation logic for user operations since these functionality
22+
* This contract does not implement validation logic for user operations since this functionality
2323
* is often delegated to self-contained validation modules. Developers must install a validator module
2424
* upon initialization (or any other mechanism to enable execution from the account):
2525
*
@@ -40,7 +40,12 @@ import {Account} from "../Account.sol";
4040
* internal virtual functions {_extractUserOpValidator} and {_extractSignatureValidator}. Both are implemented
4141
* following common practices. However, this part is not standardized in ERC-7579 (or in any follow-up ERC). Some
4242
* accounts may want to override these internal functions.
43+
* * When combined with {ERC7739}, resolution ordering of {isValidSignature} may have an impact ({ERC7739} does not
44+
* call super). Manual resolution might be necessary.
45+
* * Static calls (using callType `0xfe`) are currently NOT supported.
4346
* ====
47+
*
48+
* WARNING: Removing all validator modules will render the account inoperable, as no user operations can be validated thereafter.
4449
*/
4550
abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC7579AccountConfig, IERC7579ModuleConfig {
4651
using Bytes for *;
@@ -163,8 +168,8 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
163168
* @dev Implement ERC-1271 through IERC7579Validator modules. If module based validation fails, fallback to
164169
* "native" validation by the abstract signer.
165170
*
166-
* NOTE: when combined with {ERC7739} (for example through {Account}), resolution ordering may have an impact
167-
* ({ERC7739} does not call super). Manual resolution might be necessary.
171+
* NOTE: when combined with {ERC7739}, resolution ordering may have an impact ({ERC7739} does not call super).
172+
* Manual resolution might be necessary.
168173
*/
169174
function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) {
170175
// check signature length is enough for extraction
@@ -173,10 +178,10 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
173178
// if module is not installed, skip
174179
if (isModuleInstalled(MODULE_TYPE_VALIDATOR, module, Calldata.emptyBytes())) {
175180
// try validation, skip any revert
176-
try IERC7579Validator(module).isValidSignatureWithSender(address(this), hash, innerSignature) returns (
181+
try IERC7579Validator(module).isValidSignatureWithSender(msg.sender, hash, innerSignature) returns (
177182
bytes4 magic
178183
) {
179-
if (magic == IERC1271.isValidSignature.selector) return magic;
184+
return magic;
180185
} catch {}
181186
}
182187
}
@@ -220,8 +225,8 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
220225
/**
221226
* @dev Installs a module of the given type with the given initialization data.
222227
*
223-
* For the fallback module type, the `initData` is expected to be a tuple of a 4-byte selector and the
224-
* rest of the data to be sent to the handler when calling {IERC7579Module-onInstall}.
228+
* For the fallback module type, the `initData` is expected to be the (packed) concatenation of a 4-byte
229+
* selector and the rest of the data to be sent to the handler when calling {IERC7579Module-onInstall}.
225230
*
226231
* Requirements:
227232
*
@@ -259,14 +264,16 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
259264
/**
260265
* @dev Uninstalls a module of the given type with the given de-initialization data.
261266
*
262-
* For the fallback module type, the `deInitData` is expected to be a tuple of a 4-byte selector and the
263-
* rest of the data to be sent to the handler when calling {IERC7579Module-onUninstall}.
267+
* For the fallback module type, the `deInitData` is expected to be the (packed) concatenation of a 4-byte
268+
* selector and the rest of the data to be sent to the handler when calling {IERC7579Module-onUninstall}.
264269
*
265270
* Requirements:
266271
*
267272
* * Module must be already installed. Reverts with {ERC7579UninstalledModule} otherwise.
268273
*/
269274
function _uninstallModule(uint256 moduleTypeId, address module, bytes memory deInitData) internal virtual {
275+
require(supportsModule(moduleTypeId), ERC7579Utils.ERC7579UnsupportedModuleType(moduleTypeId));
276+
270277
if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
271278
require(_validators.remove(module), ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module));
272279
} else if (moduleTypeId == MODULE_TYPE_EXECUTOR) {
@@ -336,9 +343,10 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
336343
* ```
337344
* <module address (20 bytes)> | <key (4 bytes)> | <nonce (8 bytes)>
338345
* ```
339-
* NOTE: The default behavior of this function replicated the behavior of
340-
* https://github.com/rhinestonewtf/safe7579/blob/bb29e8b1a66658790c4169e72608e27d220f79be/src/Safe7579.sol#L266[Safe adapter] and
341-
* https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L227[Etherspot's Prime Account].
346+
* NOTE: The default behavior of this function replicates the behavior of
347+
* https://github.com/rhinestonewtf/safe7579/blob/bb29e8b1a66658790c4169e72608e27d220f79be/src/Safe7579.sol#L266[Safe adapter],
348+
* https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L227[Etherspot's Prime Account], and
349+
* https://github.com/erc7579/erc7579-implementation/blob/16138d1afd4e9711f6c1425133538837bd7787b5/src/MSAAdvanced.sol#L247[ERC7579 reference implementation].
342350
*
343351
* This is not standardized in ERC-7579 (or in any follow-up ERC). Some accounts may want to override these internal functions.
344352
*
@@ -359,10 +367,11 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
359367
* <module address (20 bytes)> | <signature data>
360368
* ```
361369
*
362-
* NOTE: The default behavior of this function replicated the behavior of
370+
* NOTE: The default behavior of this function replicates the behavior of
363371
* https://github.com/rhinestonewtf/safe7579/blob/bb29e8b1a66658790c4169e72608e27d220f79be/src/Safe7579.sol#L350[Safe adapter],
364-
* https://github.com/bcnmy/nexus/blob/54f4e19baaff96081a8843672977caf712ef19f4/contracts/Nexus.sol#L239[Biconomy's Nexus] and
365-
* https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L252[Etherspot's Prime Account]
372+
* https://github.com/bcnmy/nexus/blob/54f4e19baaff96081a8843672977caf712ef19f4/contracts/Nexus.sol#L239[Biconomy's Nexus],
373+
* https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L252[Etherspot's Prime Account], and
374+
* https://github.com/erc7579/erc7579-implementation/blob/16138d1afd4e9711f6c1425133538837bd7787b5/src/MSAAdvanced.sol#L296[ERC7579 reference implementation].
366375
*
367376
* This is not standardized in ERC-7579 (or in any follow-up ERC). Some accounts may want to override these internal functions.
368377
*/
@@ -375,10 +384,10 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
375384
/**
376385
* @dev Extract the function selector from initData/deInitData for MODULE_TYPE_FALLBACK
377386
*
378-
* NOTE: If we had calldata here, we would could use calldata slice which are cheaper to manipulate and don't
379-
* require actual copy. However, this would require `_installModule` to get a calldata bytes object instead of a
380-
* memory bytes object. This would prevent calling `_installModule` from a contract constructor and would force
381-
* the use of external initializers. That may change in the future, as most accounts will probably be deployed as
387+
* NOTE: If we had calldata here, we could use calldata slice which are cheaper to manipulate and don't require
388+
* actual copy. However, this would require `_installModule` to get a calldata bytes object instead of a memory
389+
* bytes object. This would prevent calling `_installModule` from a contract constructor and would force the use
390+
* of external initializers. That may change in the future, as most accounts will probably be deployed as
382391
* clones/proxy/ERC-7702 delegates and therefore rely on initializers anyway.
383392
*/
384393
function _decodeFallbackData(

contracts/account/extensions/AccountERC7579Hooked.sol

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.24;
3+
pragma solidity ^0.8.27;
44

55
import {IERC7579Hook, MODULE_TYPE_HOOK} from "@openzeppelin/contracts/interfaces/draft-IERC7579.sol";
66
import {ERC7579Utils, Mode} from "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol";
@@ -21,6 +21,9 @@ import {AccountERC7579} from "./AccountERC7579.sol";
2121
abstract contract AccountERC7579Hooked is AccountERC7579 {
2222
address private _hook;
2323

24+
/// @dev A hook module is already present. This contract only supports one hook module.
25+
error ERC7579HookModuleAlreadyPresent(address hook);
26+
2427
/**
2528
* @dev Calls {IERC7579Hook-preCheck} before executing the modified function and {IERC7579Hook-postCheck}
2629
* thereafter.
@@ -35,6 +38,12 @@ abstract contract AccountERC7579Hooked is AccountERC7579 {
3538
if (hook_ != address(0)) IERC7579Hook(hook_).postCheck(hookData);
3639
}
3740

41+
/// @inheritdoc AccountERC7579
42+
function accountId() public view virtual override returns (string memory) {
43+
// vendorname.accountname.semver
44+
return "@openzeppelin/community-contracts.AccountERC7579Hooked.v0.0.0";
45+
}
46+
3847
/// @dev Returns the hook module address if installed, or `address(0)` otherwise.
3948
function hook() public view virtual returns (address) {
4049
return _hook;
@@ -63,7 +72,7 @@ abstract contract AccountERC7579Hooked is AccountERC7579 {
6372
bytes memory initData
6473
) internal virtual override withHook {
6574
if (moduleTypeId == MODULE_TYPE_HOOK) {
66-
require(_hook == address(0), ERC7579Utils.ERC7579AlreadyInstalledModule(moduleTypeId, module));
75+
require(_hook == address(0), ERC7579HookModuleAlreadyPresent(_hook));
6776
_hook = module;
6877
}
6978
super._installModule(moduleTypeId, module, initData);

contracts/account/extensions/ERC7821.sol

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import {IERC7821} from "../../interfaces/IERC7821.sol";
77
import {Account} from "../Account.sol";
88

99
/**
10-
* @dev Minimal batch executor following ERC-7821. Only supports basic mode (no optional "opData").
10+
* @dev Minimal batch executor following ERC-7821.
11+
*
12+
* Only supports supports single batch mode (`0x01000000000000000000`). Does not support optional "opData".
1113
*/
1214
abstract contract ERC7821 is IERC7821 {
1315
using ERC7579Utils for *;
@@ -18,7 +20,7 @@ abstract contract ERC7821 is IERC7821 {
1820
* @dev Executes the calls in `executionData` with no optional `opData` support.
1921
*
2022
* NOTE: Access to this function is controlled by {_erc7821AuthorizedExecutor}. Changing access permissions, for
21-
* example to approve calls by the ERC-4337 entrypoint, should be implement by overriding it.
23+
* example to approve calls by the ERC-4337 entrypoint, should be implemented by overriding it.
2224
*
2325
* Reverts and bubbles up error if any call fails.
2426
*/

contracts/mocks/account/AccountERC7579Mock.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.24;
3+
pragma solidity ^0.8.27;
44

55
import {MODULE_TYPE_VALIDATOR} from "@openzeppelin/contracts/interfaces/draft-IERC7579.sol";
66
import {AccountERC7579} from "../../account/extensions/AccountERC7579.sol";

contracts/mocks/account/AccountERC7702WithModulesMock.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.24;
3+
pragma solidity ^0.8.27;
44

55
import {AbstractSigner} from "../../utils/cryptography/AbstractSigner.sol";
66
import {Account} from "../../account/Account.sol";

contracts/mocks/account/modules/ERC7579ValidatorMock.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ abstract contract ERC7579ValidatorMock is ERC7579ModuleMock(MODULE_TYPE_VALIDATO
3333
}
3434

3535
function isValidSignatureWithSender(
36-
address sender,
36+
address /*sender*/,
3737
bytes32 hash,
3838
bytes calldata signature
3939
) public view virtual returns (bytes4) {
4040
return
41-
SignatureChecker.isValidSignatureNow(_associatedSigners[sender], hash, signature)
41+
SignatureChecker.isValidSignatureNow(_associatedSigners[msg.sender], hash, signature)
4242
? IERC1271.isValidSignature.selector
4343
: bytes4(0xffffffff);
4444
}

contracts/token/ERC20/extensions/ERC20Bridgeable.sol

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {IERC7802} from "../../../interfaces/IERC7802.sol";
1616
abstract contract ERC20Bridgeable is ERC20, ERC165, IERC7802 {
1717
/// @dev Modifier to restrict access to the token bridge.
1818
modifier onlyTokenBridge() {
19+
// Token bridge should never be impersonated using a relayer/forwarder. Using msg.sender is preferable to
20+
// _msgSender() here, both for cost and security reasons.
1921
_checkTokenBridge(msg.sender);
2022
_;
2123
}
@@ -30,15 +32,15 @@ abstract contract ERC20Bridgeable is ERC20, ERC165, IERC7802 {
3032
*/
3133
function crosschainMint(address to, uint256 value) public virtual override onlyTokenBridge {
3234
_mint(to, value);
33-
emit CrosschainMint(to, value, msg.sender);
35+
emit CrosschainMint(to, value, _msgSender());
3436
}
3537

3638
/**
3739
* @dev See {IERC7802-crosschainBurn}. Emits a {CrosschainBurn} event.
3840
*/
3941
function crosschainBurn(address from, uint256 value) public virtual override onlyTokenBridge {
4042
_burn(from, value);
41-
emit CrosschainBurn(from, value, msg.sender);
43+
emit CrosschainBurn(from, value, _msgSender());
4244
}
4345

4446
/**

contracts/utils/cryptography/ERC7739.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ abstract contract ERC7739 is AbstractSigner, EIP712, IERC1271 {
3838
*/
3939
function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4 result) {
4040
// For the hash `0x7739773977397739773977397739773977397739773977397739773977397739` and an empty signature,
41-
// we return the magic value too as it's assumed impossible to find a preimage for it that can be used maliciously.
42-
// Useful for simulation purposes and to validate whether the contract supports ERC-7739.
41+
// we return the magic value `0x77390001` as it's assumed impossible to find a preimage for it that can be used
42+
// maliciously. Useful for simulation purposes and to validate whether the contract supports ERC-7739.
4343
return
4444
(_isValidNestedTypedDataSignature(hash, signature) || _isValidNestedPersonalSignSignature(hash, signature))
4545
? IERC1271.isValidSignature.selector

0 commit comments

Comments
 (0)