Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Compilation without via-ir #156

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 64 additions & 40 deletions contracts/Nexus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,17 @@
import { ExecutionHelper } from "./base/ExecutionHelper.sol";
import { IValidator } from "./interfaces/modules/IValidator.sol";
import { MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK, MODULE_TYPE_HOOK, MODULE_TYPE_MULTI } from "./types/Constants.sol";
import { ModeLib, ExecutionMode, ExecType, CallType, CALLTYPE_BATCH, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL, EXECTYPE_DEFAULT, EXECTYPE_TRY } from "./lib/ModeLib.sol";
import {
ModeLib,
ExecutionMode,
ExecType,
CallType,
CALLTYPE_BATCH,
CALLTYPE_SINGLE,
CALLTYPE_DELEGATECALL,
EXECTYPE_DEFAULT,
EXECTYPE_TRY
} from "./lib/ModeLib.sol";
import { NonceLib } from "./lib/NonceLib.sol";

/// @title Nexus - Smart Account
Expand Down Expand Up @@ -51,7 +61,9 @@

/// @notice Initializes the smart account with the specified entry point.
constructor(address anEntryPoint) {
require(address(anEntryPoint) != address(0), EntryPointCanNotBeZero());
if (address(anEntryPoint) == address(0)) {
revert EntryPointCanNotBeZero();
}
_ENTRYPOINT = anEntryPoint;
_initModuleManager();
}
Expand All @@ -78,15 +90,25 @@
PackedUserOperation calldata op,
bytes32 userOpHash,
uint256 missingAccountFunds
) external virtual payPrefund(missingAccountFunds) onlyEntryPoint returns (uint256 validationData) {
)
external
virtual
payPrefund(missingAccountFunds)
onlyEntryPoint
returns (uint256 validationData)
{
address validator = op.nonce.getValidator();
if (op.nonce.isModuleEnableMode()) {
PackedUserOperation memory userOp = op;
userOp.signature = _enableMode(userOpHash, op.signature);
require(_isValidatorInstalled(validator), ValidatorNotInstalled(validator));
if (!_isValidatorInstalled(validator)) {
revert ValidatorNotInstalled(validator);

Check warning on line 105 in contracts/Nexus.sol

View check run for this annotation

Codecov / codecov/patch

contracts/Nexus.sol#L105

Added line #L105 was not covered by tests
}
validationData = IValidator(validator).validateUserOp(userOp, userOpHash);
} else {
require(_isValidatorInstalled(validator), ValidatorNotInstalled(validator));
if (!_isValidatorInstalled(validator)) {
revert ValidatorNotInstalled(validator);
}
validationData = IValidator(validator).validateUserOp(op, userOpHash);
}
}
Expand Down Expand Up @@ -117,7 +139,14 @@
function executeFromExecutor(
ExecutionMode mode,
bytes calldata executionCalldata
) external payable onlyExecutorModule withHook withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) returns (bytes[] memory returnData) {
)
external
payable
onlyExecutorModule
withHook
withRegistry(msg.sender, MODULE_TYPE_EXECUTOR)
returns (bytes[] memory returnData)
{
(CallType callType, ExecType execType) = mode.decodeBasic();
// check if calltype is batch or single or delegate call
if (callType == CALLTYPE_SINGLE) {
Expand All @@ -138,7 +167,7 @@
function executeUserOp(PackedUserOperation calldata userOp, bytes32) external payable virtual onlyEntryPoint withHook {
bytes calldata callData = userOp.callData[4:];
(bool success, bytes memory innerCallRet) = address(this).delegatecall(callData);
if(success) { emit Executed(userOp, innerCallRet); }
if (success) emit Executed(userOp, innerCallRet);
else revert ExecutionFailed();
}

Expand Down Expand Up @@ -166,7 +195,9 @@
/// @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 withHook {
require(_isModuleInstalled(moduleTypeId, module, deInitData), ModuleNotInstalled(moduleTypeId, module));
if (!_isModuleInstalled(moduleTypeId, module, deInitData)) {
revert ModuleNotInstalled(moduleTypeId, module);
}
emit ModuleUninstalled(moduleTypeId, module);

if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
Expand All @@ -183,10 +214,14 @@
function initializeAccount(bytes calldata initData) external payable virtual {
_initModuleManager();
(address bootstrap, bytes memory bootstrapCall) = abi.decode(initData, (address, bytes));
(bool success, ) = bootstrap.delegatecall(bootstrapCall);
(bool success,) = bootstrap.delegatecall(bootstrapCall);

require(success, NexusInitializationFailed());
require(_hasValidators(), NoValidatorInstalled());
if (!success) {
revert NexusInitializationFailed();
}
if (!_hasValidators()) {
revert NoValidatorInstalled();
}
}

function setRegistry(IERC7484 newRegistry, address[] calldata attesters, uint8 threshold) external payable onlyEntryPointOrSelf {
Expand All @@ -202,7 +237,9 @@
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]));
require(_isValidatorInstalled(validator), ValidatorNotInstalled(validator));
if (!_isValidatorInstalled(validator)) {
revert ValidatorNotInstalled(validator);

Check warning on line 241 in contracts/Nexus.sol

View check run for this annotation

Codecov / codecov/patch

contracts/Nexus.sol#L241

Added line #L241 was not covered by tests
}
(bytes32 computeHash, bytes calldata truncatedSignature) = _erc1271HashForIsValidSignatureViaNestedEIP712(hash, data[20:]);
return IValidator(validator).isValidSignatureWithSender(msg.sender, computeHash, truncatedSignature);
}
Expand Down Expand Up @@ -240,9 +277,8 @@
(CallType callType, ExecType execType) = mode.decodeBasic();

// Return true if both the call type and execution type are supported.
return
(callType == CALLTYPE_SINGLE || callType == CALLTYPE_BATCH || callType == CALLTYPE_DELEGATECALL) &&
(execType == EXECTYPE_DEFAULT || execType == EXECTYPE_TRY);
return (callType == CALLTYPE_SINGLE || callType == CALLTYPE_BATCH || callType == CALLTYPE_DELEGATECALL)
&& (execType == EXECTYPE_DEFAULT || execType == EXECTYPE_TRY);
}

/// @notice Determines whether a module is installed on the smart account.
Expand Down Expand Up @@ -278,12 +314,16 @@
/// @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 withHook {
require(newImplementation != address(0), InvalidImplementationAddress());
if (newImplementation == address(0)) {
revert InvalidImplementationAddress();
}
bool res;
assembly {
res := gt(extcodesize(newImplementation), 0)
}
require(res, InvalidImplementationAddress());
if (!res) {
revert InvalidImplementationAddress();
}
// update the address() storage slot as well.
assembly {
sstore(address(), newImplementation)
Expand All @@ -304,7 +344,7 @@
/// @dev Ensures that only authorized callers can upgrade the smart contract implementation.
/// This is part of the UUPS (Universal Upgradeable Proxy Standard) pattern.
/// @param newImplementation The address of the new implementation to upgrade to.
function _authorizeUpgrade(address newImplementation) internal virtual override(UUPSUpgradeable) onlyEntryPointOrSelf {}
function _authorizeUpgrade(address newImplementation) internal virtual override(UUPSUpgradeable) onlyEntryPointOrSelf { }

/// @dev ERC1271 signature validation (Nested EIP-712 workflow).
///
Expand Down Expand Up @@ -374,10 +414,7 @@
/// you can choose a more minimalistic signature scheme like
/// `keccak256(abi.encode(address(this), hash))` instead of all these acrobatics.
/// All these are just for widespread out-of-the-box compatibility with other wallet clients.
function _erc1271HashForIsValidSignatureViaNestedEIP712(
bytes32 hash,
bytes calldata signature
) internal view virtual returns (bytes32, bytes calldata) {
function _erc1271HashForIsValidSignatureViaNestedEIP712(bytes32 hash, bytes calldata signature) internal view virtual returns (bytes32, bytes calldata) {
assembly {
// Unwraps the ERC6492 wrapper if it exists.
// See: https://eips.ethereum.org/EIPS/eip-6492
Expand All @@ -398,7 +435,7 @@
let m := mload(0x40) // Cache the free memory pointer.
// Length of the contents type.
let c := and(0xffff, calldataload(add(signature.offset, sub(signature.length, 0x20))))
for {} 1 {} {
for { } 1 { } {
let l := add(0x42, c) // Total length of appended data (32 + 32 + c + 2).
let o := add(signature.offset, sub(signature.length, l))
calldatacopy(0x20, o, 0x40) // Copy the `APP_DOMAIN_SEPARATOR` and contents struct hash.
Expand All @@ -418,15 +455,9 @@
let d := byte(0, mload(p)) // For denoting if the contents name is invalid.
d := or(gt(26, sub(d, 97)), eq(40, d)) // Starts with lowercase or '('.
// Store the end sentinel '(', and advance `p` until we encounter a '(' byte.
for {
mstore(add(p, c), 40)
} 1 {
p := add(p, 1)
} {
for { mstore(add(p, c), 40) } 1 { p := add(p, 1) } {
let b := byte(0, mload(p))
if eq(40, b) {
break
}
if eq(40, b) { break }
d := or(d, shr(b, 0x120100000001)) // Has a byte in ", )\x00".
}
mstore(p, " contents,bytes1 fields,string n")
Expand Down Expand Up @@ -460,15 +491,8 @@

/// @dev For use in `_erc1271HashForIsValidSignatureViaNestedEIP712`,
function _typedDataSignFields() private view returns (bytes32 m) {
(
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
) = eip712Domain();
(bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions) =
eip712Domain();
/// @solidity memory-safe-assembly
assembly {
m := mload(0x40) // Grab the free memory pointer.
Expand Down
29 changes: 16 additions & 13 deletions contracts/base/BaseAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ contract BaseAccount is Storage, IBaseAccount {
/// @dev Ensures the caller is either the EntryPoint or this account itself.
/// Reverts with AccountAccessUnauthorized if the check fails.
modifier onlyEntryPointOrSelf() {
require(msg.sender == _ENTRYPOINT || msg.sender == address(this), AccountAccessUnauthorized());
if (msg.sender != _ENTRYPOINT && msg.sender != address(this)) {
revert AccountAccessUnauthorized();
}
_;
}

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

Expand Down Expand Up @@ -67,9 +71,7 @@ contract BaseAccount is Storage, IBaseAccount {
/// @solidity memory-safe-assembly
assembly {
// The EntryPoint has balance accounting logic in the `receive()` function.
if iszero(call(gas(), entryPointAddress, callvalue(), codesize(), 0x00, codesize(), 0x00)) {
revert(codesize(), 0x00)
} // For gas estimation.
if iszero(call(gas(), entryPointAddress, callvalue(), codesize(), 0x00, codesize(), 0x00)) { revert(codesize(), 0x00) } // For gas estimation.
}
}

Expand Down Expand Up @@ -106,15 +108,16 @@ contract BaseAccount is Storage, IBaseAccount {
assembly {
mstore(0x20, address()) // Store the `account` argument.
mstore(0x00, 0x70a08231) // `balanceOf(address)`.
result := mul(
// Returns 0 if the EntryPoint does not exist.
mload(0x20),
and(
// The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), entryPointAddress, 0x1c, 0x24, 0x20, 0x20)
result :=
mul(
// Returns 0 if the EntryPoint does not exist.
mload(0x20),
and(
// The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), entryPointAddress, 0x1c, 0x24, 0x20, 0x20)
)
)
)
}
}

Expand Down
Loading
Loading