Skip to content

Commit

Permalink
Feat/solidity 0.8.26 (#81)
Browse files Browse the repository at this point in the history
* chore: Update solc version to 0.8.26

* chore: Update solc version to 0.8.26

* chore: Update solc version to 0.8.26

* chore: Update solc version to 0.8.26

* refactor: Change external functions to internal in TestNexusERC721Integration contract

* refactor: Change function visibility from external to internal in TestHelper contract

* chore: Update npm dependencies to latest versions

* chore: Update solidity version to 0.8.26 with viaIR optimization

* chore: Update solidity version to 0.8.26 with viaIR optimization

* lint fix

* refactor: Update coverage script to use --ir-minimum flag

* refactor: Update coverage script to use --ir-minimum flag

* refactor: Update coverage script to use --ir-minimum flag

* chore: Update CI workflow to include git pull before committing gas report changes

* chore: Update CI workflow to include git pull before committing gas report changes

* refactor: Update coverage script to remove --ir-minimum flag

* chore: Update CI workflow to work on pr only

* feat: Update ModuleWhitelistFactory to use isModuleWhitelisted instead of isWhitelisted

The commit updates the ModuleWhitelistFactory contract to use the isModuleWhitelisted function instead of the deprecated isWhitelisted function. This change ensures that all modules are properly whitelisted before execution.

* push new gas report

* feat: Update solidity version to 0.8.26 in AbstractNexusFactory.sol

* Update solidity version to 0.8.26 in AbstractNexusFactory.sol

* feat: Update solidity version to 0.8.26 in BootstrapLib.sol

* feat: Add error messages for new events in EventsAndErrors.sol

* feat: Update TestBiconomyMetaFactory_Deployments contract to handle revert message change

* refactor: Update NexusAccountFactory contract for improved readability and maintainability

* refactor: Restrict fallback handler manipulation in ModuleManager.sol

The commit restricts the manipulation of the fallback handler in the ModuleManager contract to ensure the account's security and integrity. It prevents unauthorized uninstallation and reinstallation of the validator module, which could compromise the account's security. Additionally, it checks for the presence of an existing fallback handler to avoid overwriting it and causing unexpected behavior.

* feat: Add error handling for invalid EntryPoint address

The commit adds error handling for an invalid EntryPoint address in the Stakeable contract. This ensures that only valid addresses can be used when adding, unlocking, or withdrawing stakes.

* refactor: Update AbstractNexusFactory constructor to use require instead of revert

The commit updates the constructor of the AbstractNexusFactory contract to use the require statement instead of revert. This change improves code readability and follows best practices for error handling.

* refactor: Update BiconomyMetaFactory constructor to use require instead of revert

The commit updates the constructor of the BiconomyMetaFactory contract to use the require statement instead of revert. This change improves code readability and follows best practices for error handling.

* refactor: Use require instead of revert in ModuleWhitelistFactory constructor and addModuleToWhitelist function

The commit updates the constructor of the ModuleWhitelistFactory contract to use the require statement instead of revert. This change improves code readability and follows best practices for error handling.

It also updates the addModuleToWhitelist function to use require instead of revert. This ensures that the module address being added to the whitelist is not a zero address.

Refactor the ModuleWhitelistFactory contract to improve code readability and maintainability.

* refactor: Update Stakeable contract error handling for invalid EntryPoint address

* remove natspec

* refactor: Add InnerCallFailed error to INexusEventsAndErrors.sol

The commit adds the InnerCallFailed error to the INexusEventsAndErrors.sol interface. This error is thrown when an inner call fails. This addition enhances the error handling capabilities of the interface.

Refactor the INexusEventsAndErrors.sol interface to include the InnerCallFailed error.

* refactor: Use require instead of revert in K1ValidatorFactory constructor

The commit updates the constructor of the K1ValidatorFactory contract to use the require statement instead of revert. This change improves code readability and follows best practices for error handling.

* Update  GAS_REPORT.md and gas_report.json

* lint fix

* lint fix

* refactor: Update Stakeable contract error handling for invalid EntryPoint address
  • Loading branch information
Aboudjem authored Jun 3, 2024
1 parent d63d015 commit 48a73ee
Show file tree
Hide file tree
Showing 115 changed files with 847 additions and 924 deletions.
222 changes: 111 additions & 111 deletions .github/gas_report.json

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion .solcover.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
module.exports = {
skipFiles: ["test", "/lib", "/utils", "/mocks", "contracts/mocks", "lib/ModuleTypeLib", "contracts/mocks"],
skipFiles: [
"test",
"/lib",
"/utils",
"/mocks",
"contracts/mocks",
"lib/ModuleTypeLib",
"contracts/mocks",
],
};
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": ["error", "^0.8.24"],
"compiler-version": ["error", "^0.8.26"],
"func-visibility": ["error", { "ignoreConstructors": true }],
"reentrancy": "error",
"state-visibility": "error",
Expand Down
110 changes: 55 additions & 55 deletions GAS_REPORT.md

Large diffs are not rendered by default.

63 changes: 22 additions & 41 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,25 @@
{
"codecov": {
"require_ci_to_pass": true,
"notify": {
"after_n_builds": 1
}
},
"coverage": {
"status": {
"project": {
"default": {
"target": 80.0
}
},
"patch": {
"default": {
"target": 80.0
}
}
}
},
"comment": {
"layout": "header, diff, files, footer"
},
"flags": {
"foundry": {
"paths": [
"^contracts/.*"
]
"codecov": { "require_ci_to_pass": true, "notify": { "after_n_builds": 1 } },
"coverage":
{
"status":
{
"project": { "default": { "target": 80.0 } },
"patch": { "default": { "target": 80.0 } },
},
},
"hardhat": {
"paths": [
"^contracts/.*"
]
}
},
"ignore": [
"(?s:scripts/[^\\/]*)\\Z",
"(?s:contracts/mocks/[^\\/]*)\\Z",
"(?s:test/[^\\/]*)\\Z",
"^scripts/.*",
"^test/.*"
]
"comment": { "layout": "header, diff, files, footer" },
"flags":
{
"foundry": { "paths": ["^contracts/.*"] },
"hardhat": { "paths": ["^contracts/.*"] },
},
"ignore":
[
"(?s:scripts/[^\\/]*)\\Z",
"(?s:contracts/mocks/[^\\/]*)\\Z",
"(?s:test/[^\\/]*)\\Z",
"^scripts/.*",
"^test/.*",
],
}
51 changes: 26 additions & 25 deletions contracts/Nexus.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

// ──────────────────────────────────────────────────────────────────────────────
// _ __ _ __
Expand Down Expand Up @@ -51,12 +51,10 @@ contract Nexus is INexus, EIP712, BaseAccount, ExecutionHelper, ModuleManager, U
/// @dev `keccak256("PersonalSign(bytes prefixed)")`.
bytes32 internal constant _PERSONAL_SIGN_TYPEHASH = 0x983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de;

/// @notice Initializes the smart account by setting up the module manager and state.
/// @notice Initializes the smart account with the specified entry point.
constructor(address anEntryPoint) {
_SELF = address(this);
if (address(anEntryPoint) == address(0)) {
revert EntryPointCanNotBeZero();
}
require(address(anEntryPoint) != address(0), EntryPointCanNotBeZero());
_ENTRYPOINT = anEntryPoint;
_initModuleManager();
}
Expand Down Expand Up @@ -163,7 +161,7 @@ contract Nexus is INexus, EIP712, BaseAccount, ExecutionHelper, ModuleManager, U
// Perform the call to the target contract with the decoded data.
(success, innerCallRet) = target.call(data);
// Ensure the call was successful.
require(success, "inner call failed");
require(success, InnerCallFailed());
}

// Emit the Executed event with the user operation and inner call return data.
Expand All @@ -181,12 +179,12 @@ contract Nexus is INexus, EIP712, BaseAccount, ExecutionHelper, ModuleManager, U
/// @dev This function can only be called by the EntryPoint or the account itself for security reasons.
/// @dev This function also goes through hook checks via withHook modifier.
function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable onlyEntryPointOrSelf withHook {
if (module == address(0)) revert ModuleAddressCanNotBeZero();
if (!IModule(module).isModuleType(moduleTypeId)) revert MismatchModuleTypeId(moduleTypeId);
if (_isModuleInstalled(moduleTypeId, module, initData)) {
revert ModuleAlreadyInstalled(moduleTypeId, module);
}
require(module != address(0), ModuleAddressCanNotBeZero());
require(IModule(module).isModuleType(moduleTypeId), MismatchModuleTypeId(moduleTypeId));
require(!_isModuleInstalled(moduleTypeId, module, initData), ModuleAlreadyInstalled(moduleTypeId, module));

emit ModuleInstalled(moduleTypeId, module);

if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
_installValidator(module, initData);
} else if (moduleTypeId == MODULE_TYPE_EXECUTOR) {
Expand All @@ -210,24 +208,27 @@ contract Nexus is INexus, EIP712, BaseAccount, ExecutionHelper, ModuleManager, U
/// @param deInitData De-initialization data for the module.
/// @dev Ensures that the operation is authorized and valid before proceeding with the uninstallation.
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable onlyEntryPointOrSelf {
// Should be able to validate passed moduleTypeId agaisnt the provided module
if (!IModule(module).isModuleType(moduleTypeId)) revert MismatchModuleTypeId(moduleTypeId);
if (!_isModuleInstalled(moduleTypeId, module, deInitData)) {
revert ModuleNotInstalled(moduleTypeId, module);
}
require(IModule(module).isModuleType(moduleTypeId), MismatchModuleTypeId(moduleTypeId));
require(_isModuleInstalled(moduleTypeId, module, deInitData), ModuleNotInstalled(moduleTypeId, module));

emit ModuleUninstalled(moduleTypeId, module);
if (moduleTypeId == MODULE_TYPE_VALIDATOR) _uninstallValidator(module, deInitData);
else if (moduleTypeId == MODULE_TYPE_EXECUTOR) _uninstallExecutor(module, deInitData);
else if (moduleTypeId == MODULE_TYPE_FALLBACK) _uninstallFallbackHandler(module, deInitData);
else if (moduleTypeId == MODULE_TYPE_HOOK) _uninstallHook(module, deInitData);

if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
_uninstallValidator(module, deInitData);
} else if (moduleTypeId == MODULE_TYPE_EXECUTOR) {
_uninstallExecutor(module, deInitData);
} else if (moduleTypeId == MODULE_TYPE_FALLBACK) {
_uninstallFallbackHandler(module, deInitData);
} else if (moduleTypeId == MODULE_TYPE_HOOK) {
_uninstallHook(module, deInitData);
}
}

function initializeAccount(bytes calldata initData) external payable virtual {
// checks if already initialized and reverts before setting the state to initialized
_initModuleManager();
(address bootstrap, bytes memory bootstrapCall) = abi.decode(initData, (address, bytes));
(bool success, ) = bootstrap.delegatecall(bootstrapCall);
if (!success) revert NexusInitializationFailed();
require(success, NexusInitializationFailed());
}

/// @notice Validates a signature according to ERC-1271 standards.
Expand All @@ -239,7 +240,7 @@ contract Nexus is INexus, EIP712, BaseAccount, ExecutionHelper, ModuleManager, U
function isValidSignature(bytes32 hash, bytes calldata data) external view virtual override returns (bytes4) {
// First 20 bytes of data will be validator address and rest of the bytes is complete signature.
address validator = address(bytes20(data[0:20]));
if (!_isValidatorInstalled(validator)) revert InvalidModule(validator);
require(_isValidatorInstalled(validator), InvalidModule(validator));
(bytes32 computeHash, bytes calldata truncatedSignature) = _erc1271HashForIsValidSignatureViaNestedEIP712(hash, data[20:]);
return IValidator(validator).isValidSignatureWithSender(msg.sender, computeHash, truncatedSignature);
}
Expand Down Expand Up @@ -312,12 +313,12 @@ contract Nexus is INexus, EIP712, BaseAccount, ExecutionHelper, ModuleManager, U
/// @param newImplementation The address of the new contract implementation.
/// @param data The calldata to be sent to the new implementation.
function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual override onlyEntryPointOrSelf {
if (newImplementation == address(0)) revert InvalidImplementationAddress();
require(newImplementation != address(0), InvalidImplementationAddress());
bool res;
assembly {
res := gt(extcodesize(newImplementation), 0)
}
if (res == false) revert InvalidImplementationAddress();
require(res, InvalidImplementationAddress());
// update the address() storage slot as well.
assembly {
sstore(address(), newImplementation)
Expand Down
10 changes: 3 additions & 7 deletions contracts/base/BaseAccount.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

// ──────────────────────────────────────────────────────────────────────────────
// _ __ _ __
Expand Down Expand Up @@ -34,18 +34,14 @@ contract BaseAccount is IBaseAccount {
/// @dev Ensures the caller is either the EntryPoint or this account itself.
/// Reverts with AccountAccessUnauthorized if the check fails.
modifier onlyEntryPointOrSelf() {
if (!(msg.sender == _ENTRYPOINT || msg.sender == address(this))) {
revert AccountAccessUnauthorized();
}
require(msg.sender == _ENTRYPOINT || msg.sender == address(this), AccountAccessUnauthorized());
_;
}

/// @dev Ensures the caller is the EntryPoint.
/// Reverts with AccountAccessUnauthorized if the check fails.
modifier onlyEntryPoint() {
if (msg.sender != _ENTRYPOINT) {
revert AccountAccessUnauthorized();
}
require(msg.sender == _ENTRYPOINT, AccountAccessUnauthorized());
_;
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/base/ExecutionHelper.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

// ──────────────────────────────────────────────────────────────────────────────
// _ __ _ __
Expand Down
25 changes: 8 additions & 17 deletions contracts/base/ModuleManager.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

// ──────────────────────────────────────────────────────────────────────────────
// _ __ _ __
Expand Down Expand Up @@ -36,7 +36,7 @@ contract ModuleManager is Storage, Receiver, IModuleManagerEventsAndErrors {

/// @notice Ensures the message sender is a registered executor module.
modifier onlyExecutorModule() virtual {
if (!_getAccountStorage().executors.contains(msg.sender)) revert InvalidModule(msg.sender);
require(_getAccountStorage().executors.contains(msg.sender), InvalidModule(msg.sender));
_;
}

Expand All @@ -58,7 +58,7 @@ contract ModuleManager is Storage, Receiver, IModuleManagerEventsAndErrors {
FallbackHandler storage $fallbackHandler = _getAccountStorage().fallbacks[msg.sig];
address handler = $fallbackHandler.handler;
CallType calltype = $fallbackHandler.calltype;
if (handler == address(0)) revert MissingFallbackHandler(msg.sig);
require(handler != address(0), MissingFallbackHandler(msg.sig));

if (calltype == CALLTYPE_STATIC) {
assembly {
Expand Down Expand Up @@ -157,11 +157,8 @@ contract ModuleManager is Storage, Receiver, IModuleManagerEventsAndErrors {

// Check if the account has at least one validator installed before proceeding
// Having at least one validator is a requirement for the account to function properly
if (prev == address(0x01)) {
if (validators.getNext(validator) == address(0x01)) {
revert CannotRemoveLastValidator();
}
}
require(!(prev == address(0x01) && validators.getNext(validator) == address(0x01)), CannotRemoveLastValidator());

validators.pop(prev, validator);
IValidator(validator).onUninstall(disableModuleData);
}
Expand All @@ -188,9 +185,7 @@ contract ModuleManager is Storage, Receiver, IModuleManagerEventsAndErrors {
/// @param data Initialization data to configure the hook upon installation.
function _installHook(address hook, bytes calldata data) internal virtual {
address currentHook = _getHook();
if (currentHook != address(0)) {
revert HookAlreadyInstalled(currentHook);
}
require(currentHook == address(0), HookAlreadyInstalled(currentHook));
_setHook(hook);
IHook(hook).onInstall(data);
}
Expand Down Expand Up @@ -228,15 +223,11 @@ contract ModuleManager is Storage, Receiver, IModuleManagerEventsAndErrors {
// If a validator module is uninstalled and reinstalled without proper authorization, it can compromise
// the account's security and integrity. By restricting these selectors, we ensure that the fallback handler
// cannot be manipulated to disrupt the expected behavior and security of the account.
if (selector == bytes4(0x6d61fe70) || selector == bytes4(0x8a91b0e3)) {
revert FallbackSelectorForbidden();
}
require(!(selector == bytes4(0x6d61fe70) || selector == bytes4(0x8a91b0e3)), FallbackSelectorForbidden());

// Revert if a fallback handler is already installed for the given selector.
// This check ensures that we do not overwrite an existing fallback handler, which could lead to unexpected behavior.
if (_isFallbackHandlerInstalled(selector)) {
revert FallbackAlreadyInstalledForSelector(selector);
}
require(!_isFallbackHandlerInstalled(selector), FallbackAlreadyInstalledForSelector(selector));

// Store the fallback handler and its call type in the account storage.
// This maps the function selector to the specified fallback handler and call type.
Expand Down
2 changes: 1 addition & 1 deletion contracts/base/Storage.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

// ──────────────────────────────────────────────────────────────────────────────
// _ __ _ __
Expand Down
11 changes: 7 additions & 4 deletions contracts/common/Stakeable.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

// ──────────────────────────────────────────────────────────────────────────────
// _ __ _ __
Expand All @@ -25,6 +25,9 @@ import { IStakeable } from "../interfaces/common/IStakeable.sol";
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
contract Stakeable is Ownable, IStakeable {
/// @notice Error thrown when an invalid EntryPoint address is provided.
error InvalidEntryPointAddress();

constructor(address newOwner) {
_setOwner(newOwner);
}
Expand All @@ -34,15 +37,15 @@ contract Stakeable is Ownable, IStakeable {
/// @param epAddress The address of the EntryPoint where the stake is added.
/// @param unstakeDelaySec The delay in seconds before the stake can be unlocked.
function addStake(address epAddress, uint32 unstakeDelaySec) external payable onlyOwner {
require(epAddress != address(0), "Invalid EP address");
require(epAddress != address(0), InvalidEntryPointAddress());
IEntryPoint(epAddress).addStake{ value: msg.value }(unstakeDelaySec);
}

/// @notice Unlocks the stake on an EntryPoint.
/// @dev This starts the unstaking delay after which funds can be withdrawn.
/// @param epAddress The address of the EntryPoint from which the stake is to be unlocked.
function unlockStake(address epAddress) external onlyOwner {
require(epAddress != address(0), "Invalid EP address");
require(epAddress != address(0), InvalidEntryPointAddress());
IEntryPoint(epAddress).unlockStake();
}

Expand All @@ -51,7 +54,7 @@ contract Stakeable is Ownable, IStakeable {
/// @param epAddress The address of the EntryPoint where the stake is withdrawn from.
/// @param withdrawAddress The address to receive the withdrawn stake.
function withdrawStake(address epAddress, address payable withdrawAddress) external onlyOwner {
require(epAddress != address(0), "Invalid EP address");
require(epAddress != address(0), InvalidEntryPointAddress());
IEntryPoint(epAddress).withdrawStake(withdrawAddress);
}
}
6 changes: 2 additions & 4 deletions contracts/factory/AbstractNexusFactory.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

// ──────────────────────────────────────────────────────────────────────────────
// _ __ _ __
Expand Down Expand Up @@ -31,9 +31,7 @@ abstract contract AbstractNexusFactory is Stakeable, IAbstractNexusFactory {
/// @param implementation_ The address of the Nexus implementation to be used for all deployments.
/// @param owner_ The address of the owner of the factory.
constructor(address implementation_, address owner_) Stakeable(owner_) {
if (implementation_ == address(0)) {
revert ImplementationAddressCanNotBeZero();
}
require(implementation_ != address(0), ImplementationAddressCanNotBeZero());
ACCOUNT_IMPLEMENTATION = implementation_;
}

Expand Down
Loading

0 comments on commit 48a73ee

Please sign in to comment.