Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x60e03461 | 7300188 | 167 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
ModularAccount
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 50000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import { IModularAccount, ValidationConfig } from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol"; import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol"; import {ModularAccountBase} from "./ModularAccountBase.sol"; /// @title Modular Account /// @author Alchemy /// @notice This contract allows initializing with a validation config (of a validation module) to be installed on /// the account. contract ModularAccount is ModularAccountBase { constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate) ModularAccountBase(entryPoint, executionInstallDelegate) {} /// @notice Initializes the account with a validation function. /// @dev This function is only callable once. function initializeWithValidation( ValidationConfig validationConfig, bytes4[] calldata selectors, bytes calldata installData, bytes[] calldata hooks ) external virtual initializer { _installValidation(validationConfig, selectors, installData, hooks); } /// @inheritdoc IModularAccount function accountId() external pure override returns (string memory) { return "alchemy.modular-account.2.0.0"; } /// @dev Overrides ModularAccountView. function _isNativeFunction(uint32 selector) internal pure override returns (bool) { return super._isNativeFunction(selector) || selector == uint32(this.initializeWithValidation.selector); } }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; import {ExecutionManifest} from "./IExecutionModule.sol"; type ModuleEntity is bytes24; // ModuleEntity is a packed representation of a module function // Layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address // 0x________________________________________BBBBBBBB________________ // Entity ID // 0x________________________________________________0000000000000000 // unused type ValidationConfig is bytes25; // ValidationConfig is a packed representation of a validation function and flags for its configuration. // Layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address // 0x________________________________________BBBBBBBB________________ // Entity ID // 0x________________________________________________CC______________ // ValidationFlags // 0x__________________________________________________00000000000000 // unused type ValidationFlags is uint8; // ValidationFlags layout: // 0b00000___ // unused // 0b_____A__ // isGlobal // 0b______B_ // isSignatureValidation // 0b_______C // isUserOpValidation type HookConfig is bytes25; // HookConfig is a packed representation of a hook function and flags for its configuration. // Layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address // 0x________________________________________BBBBBBBB________________ // Entity ID // 0x________________________________________________CC______________ // Hook Flags // // Hook flags layout: // 0b00000___ // unused // 0b_____A__ // hasPre (exec only) // 0b______B_ // hasPost (exec only) // 0b_______C // hook type (0 for exec, 1 for validation) struct Call { // The target address for the account to call. address target; // The value to send with the call. uint256 value; // The calldata for the call. bytes data; } interface IModularAccount { event ExecutionInstalled(address indexed module, ExecutionManifest manifest); event ExecutionUninstalled(address indexed module, bool onUninstallSucceeded, ExecutionManifest manifest); event ValidationInstalled(address indexed module, uint32 indexed entityId); event ValidationUninstalled(address indexed module, uint32 indexed entityId, bool onUninstallSucceeded); /// @notice Standard execute method. /// @param target The target address for the account to call. /// @param value The value to send with the call. /// @param data The calldata for the call. /// @return The return data from the call. function execute(address target, uint256 value, bytes calldata data) external payable returns (bytes memory); /// @notice Standard executeBatch method. /// @dev If the target is a module, the call SHOULD revert. If any of the calls revert, the entire batch MUST /// revert. /// @param calls The array of calls. /// @return An array containing the return data from the calls. function executeBatch(Call[] calldata calls) external payable returns (bytes[] memory); /// @notice Execute a call using the specified runtime validation. /// @param data The calldata to send to the account. /// @param authorization The authorization data to use for the call. The first 24 bytes is a ModuleEntity which /// specifies which runtime validation to use, and the rest is sent as a parameter to runtime validation. function executeWithRuntimeValidation(bytes calldata data, bytes calldata authorization) external payable returns (bytes memory); /// @notice Install a module to the modular account. /// @param module The module to install. /// @param manifest the manifest describing functions to install. /// @param installData Optional data to be used by the account to handle the initial execution setup. Data /// encoding /// is implementation-specific. function installExecution(address module, ExecutionManifest calldata manifest, bytes calldata installData) external; /// @notice Uninstall a module from the modular account. /// @param module The module to uninstall. /// @param manifest the manifest describing functions to uninstall. /// @param uninstallData Optional data to be used by the account to handle the execution uninstallation. Data /// encoding is implementation-specific. function uninstallExecution(address module, ExecutionManifest calldata manifest, bytes calldata uninstallData) external; /// @notice Installs a validation function across a set of execution selectors, and optionally mark it as a /// global validation function. /// @dev This does not validate anything against the manifest - the caller must ensure validity. /// @param validationConfig The validation function to install, along with configuration flags. /// @param selectors The selectors to install the validation function for. /// @param installData Optional data to be used by the account to handle the initial validation setup. Data /// encoding is implementation-specific. /// @param hooks Optional hooks to install and associate with the validation function. Data encoding is /// implementation-specific. function installValidation( ValidationConfig validationConfig, bytes4[] calldata selectors, bytes calldata installData, bytes[] calldata hooks ) external; /// @notice Uninstall a validation function from a set of execution selectors. /// @param validationFunction The validation function to uninstall. /// @param uninstallData Optional data to be used by the account to handle the validation uninstallation. Data /// encoding is implementation-specific. /// @param hookUninstallData Optional data to be used by the account to handle hook uninstallation. Data /// encoding /// is implementation-specific. function uninstallValidation( ModuleEntity validationFunction, bytes calldata uninstallData, bytes[] calldata hookUninstallData ) external; /// @notice Return a unique identifier for the account implementation. /// @dev This function MUST return a string in the format "vendor.account.semver". The vendor and account /// names MUST NOT contain a period character. /// @return The account ID. function accountId() external view returns (string memory); }
/** ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation. ** Only one instance required on each chain. **/ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ import "./PackedUserOperation.sol"; import "./IStakeManager.sol"; import "./IAggregator.sol"; import "./INonceManager.sol"; interface IEntryPoint is IStakeManager, INonceManager { /*** * An event emitted after each successful request. * @param userOpHash - Unique identifier for the request (hash its entire content, except signature). * @param sender - The account that generates this request. * @param paymaster - If non-null, the paymaster that pays for this request. * @param nonce - The nonce value from the request. * @param success - True if the sender transaction succeeded, false if reverted. * @param actualGasCost - Actual amount paid (by account or paymaster) for this UserOperation. * @param actualGasUsed - Total gas used by this UserOperation (including preVerification, creation, * validation and execution). */ event UserOperationEvent( bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed ); /** * Account "sender" was deployed. * @param userOpHash - The userOp that deployed this account. UserOperationEvent will follow. * @param sender - The account that is deployed * @param factory - The factory used to deploy this account (in the initCode) * @param paymaster - The paymaster used by this UserOp */ event AccountDeployed( bytes32 indexed userOpHash, address indexed sender, address factory, address paymaster ); /** * An event emitted if the UserOperation "callData" reverted with non-zero length. * @param userOpHash - The request unique identifier. * @param sender - The sender of this request. * @param nonce - The nonce used in the request. * @param revertReason - The return bytes from the (reverted) call to "callData". */ event UserOperationRevertReason( bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason ); /** * An event emitted if the UserOperation Paymaster's "postOp" call reverted with non-zero length. * @param userOpHash - The request unique identifier. * @param sender - The sender of this request. * @param nonce - The nonce used in the request. * @param revertReason - The return bytes from the (reverted) call to "callData". */ event PostOpRevertReason( bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason ); /** * UserOp consumed more than prefund. The UserOperation is reverted, and no refund is made. * @param userOpHash - The request unique identifier. * @param sender - The sender of this request. * @param nonce - The nonce used in the request. */ event UserOperationPrefundTooLow( bytes32 indexed userOpHash, address indexed sender, uint256 nonce ); /** * An event emitted by handleOps(), before starting the execution loop. * Any event emitted before this event, is part of the validation. */ event BeforeExecution(); /** * Signature aggregator used by the following UserOperationEvents within this bundle. * @param aggregator - The aggregator used for the following UserOperationEvents. */ event SignatureAggregatorChanged(address indexed aggregator); /** * A custom revert error of handleOps, to identify the offending op. * Should be caught in off-chain handleOps simulation and not happen on-chain. * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts. * NOTE: If simulateValidation passes successfully, there should be no reason for handleOps to fail on it. * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero). * @param reason - Revert reason. The string starts with a unique code "AAmn", * where "m" is "1" for factory, "2" for account and "3" for paymaster issues, * so a failure can be attributed to the correct entity. */ error FailedOp(uint256 opIndex, string reason); /** * A custom revert error of handleOps, to report a revert by account or paymaster. * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero). * @param reason - Revert reason. see FailedOp(uint256,string), above * @param inner - data from inner cought revert reason * @dev note that inner is truncated to 2048 bytes */ error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner); error PostOpReverted(bytes returnData); /** * Error case when a signature aggregator fails to verify the aggregated signature it had created. * @param aggregator The aggregator that failed to verify the signature */ error SignatureValidationFailed(address aggregator); // Return value of getSenderAddress. error SenderAddressResult(address sender); // UserOps handled, per aggregator. struct UserOpsPerAggregator { PackedUserOperation[] userOps; // Aggregator address IAggregator aggregator; // Aggregated signature bytes signature; } /** * Execute a batch of UserOperations. * No signature aggregator is used. * If any account requires an aggregator (that is, it returned an aggregator when * performing simulateValidation), then handleAggregatedOps() must be used instead. * @param ops - The operations to execute. * @param beneficiary - The address to receive the fees. */ function handleOps( PackedUserOperation[] calldata ops, address payable beneficiary ) external; /** * Execute a batch of UserOperation with Aggregators * @param opsPerAggregator - The operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts). * @param beneficiary - The address to receive the fees. */ function handleAggregatedOps( UserOpsPerAggregator[] calldata opsPerAggregator, address payable beneficiary ) external; /** * Generate a request Id - unique identifier for this request. * The request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid. * @param userOp - The user operation to generate the request ID for. * @return hash the hash of this UserOperation */ function getUserOpHash( PackedUserOperation calldata userOp ) external view returns (bytes32); /** * Gas and return values during simulation. * @param preOpGas - The gas used for validation (including preValidationGas) * @param prefund - The required prefund for this operation * @param accountValidationData - returned validationData from account. * @param paymasterValidationData - return validationData from paymaster. * @param paymasterContext - Returned by validatePaymasterUserOp (to be passed into postOp) */ struct ReturnInfo { uint256 preOpGas; uint256 prefund; uint256 accountValidationData; uint256 paymasterValidationData; bytes paymasterContext; } /** * Returned aggregated signature info: * The aggregator returned by the account, and its current stake. */ struct AggregatorStakeInfo { address aggregator; StakeInfo stakeInfo; } /** * Get counterfactual sender address. * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation. * This method always revert, and returns the address in SenderAddressResult error * @param initCode - The constructor code to be passed into the UserOperation. */ function getSenderAddress(bytes memory initCode) external; error DelegateAndRevert(bool success, bytes ret); /** * Helper method for dry-run testing. * @dev calling this method, the EntryPoint will make a delegatecall to the given data, and report (via revert) the result. * The method always revert, so is only useful off-chain for dry run calls, in cases where state-override to replace * actual EntryPoint code is less convenient. * @param target a target contract to make a delegatecall from entrypoint * @param data data to pass to target in a delegatecall */ function delegateAndRevert(address target, bytes calldata data) external; }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import { ExecutionManifest, ManifestExecutionHook } from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol"; import {HookConfig, IModularAccount} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol"; import {AccountStorage, ExecutionStorage, getAccountStorage, toSetValue} from "../account/AccountStorage.sol"; import {KnownSelectorsLib} from "../libraries/KnownSelectorsLib.sol"; import {LinkedListSet, LinkedListSetLib} from "../libraries/LinkedListSetLib.sol"; import {ModuleInstallCommonsLib} from "../libraries/ModuleInstallCommonsLib.sol"; /// @title Execution Install Delegate /// @author Alchemy /// @notice This contract acts as an external library which is meant to handle execution function installations and /// uninstallations via delegatecall. contract ExecutionInstallDelegate { using LinkedListSetLib for LinkedListSet; address internal immutable _THIS_ADDRESS; error ERC4337FunctionNotAllowed(bytes4 selector); error ExecutionFunctionAlreadySet(bytes4 selector); error ExecutionFunctionNotSet(bytes4 selector); error ExecutionHookNotSet(HookConfig hookConfig); error IModuleFunctionNotAllowed(bytes4 selector); error NullModule(); error OnlyDelegateCall(); modifier onlyDelegateCall() { if (address(this) == _THIS_ADDRESS) { revert OnlyDelegateCall(); } _; } constructor() { _THIS_ADDRESS = address(this); } // External Functions /// @notice Update components according to the manifest. function installExecution( address module, ExecutionManifest calldata manifest, bytes calldata moduleInstallData ) external onlyDelegateCall { AccountStorage storage _storage = getAccountStorage(); if (module == address(0)) { revert NullModule(); } // Update components according to the manifest. uint256 length = manifest.executionFunctions.length; for (uint256 i = 0; i < length; ++i) { bytes4 selector = manifest.executionFunctions[i].executionSelector; bool skipRuntimeValidation = manifest.executionFunctions[i].skipRuntimeValidation; bool allowGlobalValidation = manifest.executionFunctions[i].allowGlobalValidation; _setExecutionFunction(selector, skipRuntimeValidation, allowGlobalValidation, module); } length = manifest.executionHooks.length; for (uint256 i = 0; i < length; ++i) { ManifestExecutionHook memory mh = manifest.executionHooks[i]; LinkedListSet storage executionHooks = _storage.executionStorage[mh.executionSelector].executionHooks; HookConfig hookConfig = HookConfigLib.packExecHook({ _module: module, _entityId: mh.entityId, _hasPre: mh.isPreHook, _hasPost: mh.isPostHook }); ModuleInstallCommonsLib.addExecHooks(executionHooks, hookConfig); } length = manifest.interfaceIds.length; for (uint256 i = 0; i < length; ++i) { _storage.supportedIfaces[manifest.interfaceIds[i]] += 1; } ModuleInstallCommonsLib.onInstall(module, moduleInstallData, type(IModule).interfaceId); emit IModularAccount.ExecutionInstalled(module, manifest); } /// @notice Remove components according to the manifest, in reverse order (by component type) of their /// installation. function uninstallExecution(address module, ExecutionManifest calldata manifest, bytes calldata uninstallData) external onlyDelegateCall { AccountStorage storage _storage = getAccountStorage(); if (module == address(0)) { revert NullModule(); } uint256 length = manifest.executionHooks.length; for (uint256 i = 0; i < length; ++i) { ManifestExecutionHook memory mh = manifest.executionHooks[i]; LinkedListSet storage executionHooks = _storage.executionStorage[mh.executionSelector].executionHooks; HookConfig hookConfig = HookConfigLib.packExecHook({ _module: module, _entityId: mh.entityId, _hasPre: mh.isPreHook, _hasPost: mh.isPostHook }); _removeExecHooks(executionHooks, hookConfig); } length = manifest.executionFunctions.length; for (uint256 i = 0; i < length; ++i) { bytes4 selector = manifest.executionFunctions[i].executionSelector; _removeExecutionFunction(selector); } length = manifest.interfaceIds.length; for (uint256 i = 0; i < length; ++i) { _storage.supportedIfaces[manifest.interfaceIds[i]] -= 1; } // Clear the module storage for the account. bool onUninstallSuccess = ModuleInstallCommonsLib.onUninstall(module, uninstallData); emit IModularAccount.ExecutionUninstalled(module, onUninstallSuccess, manifest); } // Private Functions function _setExecutionFunction( bytes4 selector, bool skipRuntimeValidation, bool allowGlobalValidation, address module ) internal { ExecutionStorage storage _executionStorage = getAccountStorage().executionStorage[selector]; if (_executionStorage.module != address(0)) { revert ExecutionFunctionAlreadySet(selector); } // Note that there is no check for native function selectors. Installing a function with a colliding // selector will lead to the installed function being unreachable. // Make sure incoming execution function is not a function in IModule if (KnownSelectorsLib.isIModuleFunction(uint32(selector))) { revert IModuleFunctionNotAllowed(selector); } // Also make sure it doesn't collide with functions defined by ERC-4337 and called by the entry point. This // prevents a malicious module from sneaking in a function with the same selector as e.g. // `validatePaymasterUserOp` and turning the account into their own personal paymaster. if (KnownSelectorsLib.isERC4337Function(uint32(selector))) { revert ERC4337FunctionNotAllowed(selector); } _executionStorage.module = module; _executionStorage.skipRuntimeValidation = skipRuntimeValidation; _executionStorage.allowGlobalValidation = allowGlobalValidation; } function _removeExecutionFunction(bytes4 selector) internal { ExecutionStorage storage _executionStorage = getAccountStorage().executionStorage[selector]; if (_executionStorage.module == address(0)) { revert ExecutionFunctionNotSet(selector); } _executionStorage.module = address(0); _executionStorage.skipRuntimeValidation = false; _executionStorage.allowGlobalValidation = false; } function _removeExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) internal { if (!hooks.tryRemove(toSetValue(hookConfig))) { revert ExecutionHookNotSet(hookConfig); } } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {getEmptyCalldataSlice} from "@erc6900/reference-implementation/helpers/EmptyCalldataSlice.sol"; import {ExecutionManifest} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol"; import { Call, HookConfig, IModularAccount, ModuleEntity, ValidationConfig, ValidationFlags } from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {HookConfig, HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol"; import {ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol"; import {SparseCalldataSegmentLib} from "@erc6900/reference-implementation/libraries/SparseCalldataSegmentLib.sol"; import {ValidationConfigLib} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol"; import {IAccountExecute} from "@eth-infinitism/account-abstraction/interfaces/IAccountExecute.sol"; import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol"; import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol"; import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol"; import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol"; import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol"; import {_coalescePreValidation, _coalesceValidation} from "../helpers/ValidationResHelpers.sol"; import {IModularAccountBase} from "../interfaces/IModularAccountBase.sol"; import { DensePostHookData, ExecutionLib, PHCallBuffer, RTCallBuffer, SigCallBuffer, UOCallBuffer } from "../libraries/ExecutionLib.sol"; import {LinkedListSet, LinkedListSetLib} from "../libraries/LinkedListSetLib.sol"; import {MemManagementLib, MemSnapshot} from "../libraries/MemManagementLib.sol"; import { ValidationLocator, ValidationLocatorLib, ValidationLookupKey } from "../libraries/ValidationLocatorLib.sol"; import {AccountBase} from "./AccountBase.sol"; import {AccountStorage, ValidationStorage, getAccountStorage, toSetValue} from "./AccountStorage.sol"; import {AccountStorageInitializable} from "./AccountStorageInitializable.sol"; import {ModularAccountView} from "./ModularAccountView.sol"; import {ModuleManagerInternals} from "./ModuleManagerInternals.sol"; import {TokenReceiver} from "./TokenReceiver.sol"; /// @title Modular Account Base /// @author Alchemy /// @notice This abstract contract is a modular account that is compliant with ERC-6900 standard. It supports /// deferred actions during validation. abstract contract ModularAccountBase is IModularAccount, IModularAccountBase, ModularAccountView, AccountStorageInitializable, AccountBase, IERC1271, IERC165, IAccountExecute, ModuleManagerInternals, UUPSUpgradeable, TokenReceiver { using LinkedListSetLib for LinkedListSet; using ModuleEntityLib for ModuleEntity; using ValidationConfigLib for ValidationFlags; using HookConfigLib for HookConfig; using SparseCalldataSegmentLib for bytes; enum ValidationCheckingType { GLOBAL, SELECTOR, EITHER } // keccak256("EIP712Domain(uint256 chainId,address verifyingContract)") bytes32 internal constant _DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218; // keccak256("DeferredAction(uint256 nonce,uint48 deadline,bytes call)") bytes32 internal constant _DEFERRED_ACTION_TYPEHASH = 0x9b23e06584efc6b65fc854cee55011d89f86485487b6db36aed7d23884711ea3; // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 internal constant _INTERFACE_ID_INVALID = 0xffffffff; // bytes4(keccak256("isValidSignature(bytes32,bytes)")) bytes4 internal constant _1271_MAGIC_VALUE = 0x1626ba7e; bytes4 internal constant _1271_INVALID = 0xffffffff; address internal immutable _EXECUTION_INSTALL_DELEGATE; error CreateFailed(); error DeferredActionSignatureInvalid(); error RequireUserOperationContext(); error SelfCallRecursionDepthExceeded(); error SignatureValidationInvalid(ModuleEntity validationFunction); error UserOpValidationInvalid(ModuleEntity validationFunction); error UnexpectedAggregator(ModuleEntity validationFunction, address aggregator); error UnrecognizedFunction(bytes4 selector); error ValidationFunctionMissing(bytes4 selector); error DeferredValidationHasValidationHooks(); // Wraps execution of a native function with runtime validation and hooks // Used for performCreate, execute, executeBatch, installExecution, uninstallExecution, installValidation, // uninstallValidation, upgradeToAndCall, updateFallbackSignerData. modifier wrapNativeFunction() { DensePostHookData postHookData = _checkPermittedCallerAndAssociatedHooks(); _; ExecutionLib.doCachedPostHooks(postHookData); } constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate) AccountBase(entryPoint) { _disableInitializers(); _EXECUTION_INSTALL_DELEGATE = address(executionInstallDelegate); } // EXTERNAL FUNCTIONS receive() external payable {} /// @notice Fallback function /// @dev Routes calls to execution functions based on the incoming msg.sig. If there's no module associated /// with this function selector, revert. /// /// @return The raw returned data from the invoked execution function. fallback(bytes calldata) external payable returns (bytes memory) { address execModule = getAccountStorage().executionStorage[msg.sig].module; if (execModule == address(0)) { revert UnrecognizedFunction(msg.sig); } DensePostHookData postHookData = _checkPermittedCallerAndAssociatedHooks(); // execute the function, bubbling up any reverts ExecutionLib.callBubbleOnRevertTransient(execModule, 0 wei, msg.data); bytes memory execReturnData = ExecutionLib.collectReturnData(); ExecutionLib.doCachedPostHooks(postHookData); return execReturnData; } /// @inheritdoc IModularAccountBase function performCreate(uint256 value, bytes calldata initCode, bool isCreate2, bytes32 salt) external payable virtual override wrapNativeFunction returns (address createdAddr) { assembly ("memory-safe") { // Load the free memory pointer. let fmp := mload(0x40) // Get the initCode length. let len := initCode.length // Copy the initCode from callata to memory at the free memory pointer. calldatacopy(fmp, initCode.offset, len) switch isCreate2 case 1 { createdAddr := create2(value, fmp, len, salt) } default { createdAddr := create(value, fmp, len) } if iszero(createdAddr) { // If creation failed (the address returned is zero), revert with CreateFailed(). mstore(0x00, 0x7e16b8cd) revert(0x1c, 0x04) } } } /// @inheritdoc IAccountExecute /// @notice Execution function that allows UO context to be passed to execution hooks /// @dev This function is only callable by the EntryPoint function executeUserOp(PackedUserOperation calldata userOp, bytes32) external override { _requireFromEntryPoint(); ValidationLocator locator = ValidationLocatorLib.loadFromNonce(userOp.nonce); HookConfig[] memory validationAssocExecHooks = MemManagementLib.loadExecHooks(getAccountStorage().validationStorage[locator.lookupKey()]); PHCallBuffer callBuffer; if (validationAssocExecHooks.length > 0) { callBuffer = ExecutionLib.allocatePreExecHookCallBuffer(msg.data); } DensePostHookData postHookData = ExecutionLib.doPreHooks(validationAssocExecHooks, callBuffer); bytes memory callData = ExecutionLib.getExecuteUOCallData(callBuffer, userOp.callData); // Manually call self, without collecting return data unless there's a revert. ExecutionLib.callBubbleOnRevert(address(this), 0, callData); ExecutionLib.doCachedPostHooks(postHookData); } /// @inheritdoc IModularAccount /// @notice May be validated by a global validation. function execute(address target, uint256 value, bytes calldata data) external payable override wrapNativeFunction returns (bytes memory result) { ExecutionLib.callBubbleOnRevertTransient(target, value, data); // Only return data if not called by the EntryPoint if (msg.sender != address(_ENTRY_POINT)) { result = ExecutionLib.collectReturnData(); } } /// @inheritdoc IModularAccount /// @notice May be validated by a global validation function. function executeBatch(Call[] calldata calls) external payable override wrapNativeFunction returns (bytes[] memory results) { uint256 callsLength = calls.length; if (msg.sender != address(_ENTRY_POINT)) { results = new bytes[](callsLength); for (uint256 i = 0; i < callsLength; ++i) { ExecutionLib.callBubbleOnRevertTransient(calls[i].target, calls[i].value, calls[i].data); results[i] = ExecutionLib.collectReturnData(); } } else { for (uint256 i = 0; i < callsLength; ++i) { ExecutionLib.callBubbleOnRevertTransient(calls[i].target, calls[i].value, calls[i].data); } } } /// @inheritdoc IModularAccount function executeWithRuntimeValidation(bytes calldata data, bytes calldata authorization) external payable returns (bytes memory) { (ValidationLocator locator, bytes calldata authorizationData) = ValidationLocatorLib.loadFromSignature(authorization); ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[locator.lookupKey()]; // Check if the runtime validation function is allowed to be called _checkIfValidationAppliesCallData( data, locator.lookupKey(), // Unfortunately, have to avoid declaring a `bool isGlobalValidation` to avoid stack too deep issues. locator.isGlobal() ? ValidationCheckingType.GLOBAL : ValidationCheckingType.SELECTOR ); RTCallBuffer rtCallBuffer = _doRuntimeValidation(locator.lookupKey(), data, authorizationData); // If runtime validation passes, run exec hooks associated with the validator HookConfig[] memory validationAssocExecHooks = MemManagementLib.loadExecHooks(_validationStorage); PHCallBuffer phCallBuffer; if (validationAssocExecHooks.length > 0) { phCallBuffer = ExecutionLib.convertToPreHookCallBuffer(rtCallBuffer, data); } DensePostHookData postHookData = ExecutionLib.doPreHooks(validationAssocExecHooks, phCallBuffer); // Execute the call, reusing the already-allocated RT call buffers, if it exists. // In practice, this is cheaper than attempting to coalesce the (possibly two) buffers. ExecutionLib.executeRuntimeSelfCall(rtCallBuffer, data); bytes memory returnData = ExecutionLib.collectReturnData(); ExecutionLib.doCachedPostHooks(postHookData); return returnData; } /// @inheritdoc IModularAccount /// @notice May be validated by a global validation. function installExecution( address module, ExecutionManifest calldata manifest, bytes calldata moduleInstallData ) external override wrapNativeFunction { // Access params to prevent compiler unused parameter flags. (module, manifest, moduleInstallData); address delegate = _EXECUTION_INSTALL_DELEGATE; ExecutionLib.delegatecallBubbleOnRevertTransient(delegate); } /// @inheritdoc IModularAccount /// @notice May be validated by a global validation. function uninstallExecution( address module, ExecutionManifest calldata manifest, bytes calldata moduleUninstallData ) external override wrapNativeFunction { // Access params to prevent compiler unused parameter flags. (module, manifest, moduleUninstallData); address delegate = _EXECUTION_INSTALL_DELEGATE; ExecutionLib.delegatecallBubbleOnRevertTransient(delegate); } /// @inheritdoc IModularAccount /// @notice May be validated by a global validation. /// @dev This function can be used to update (to a certain degree) previously installed validation functions. /// - preValidationHook, executionHooks, and selectors can be added later. Though they won't be deleted. /// - isGlobal and isSignatureValidation can also be updated later. function installValidation( ValidationConfig validationConfig, bytes4[] calldata selectors, bytes calldata installData, bytes[] calldata hooks ) external virtual wrapNativeFunction { _installValidation(validationConfig, selectors, installData, hooks); } /// @inheritdoc IModularAccount /// @notice May be validated by a global validation. function uninstallValidation( ModuleEntity validationFunction, bytes calldata uninstallData, bytes[] calldata hookUninstallData ) external wrapNativeFunction { _uninstallValidation(validationFunction, uninstallData, hookUninstallData); } /// @inheritdoc IERC1271 function isValidSignature(bytes32 hash, bytes calldata signature) external view override returns (bytes4) { (ValidationLocator locator, bytes calldata signatureRemainder) = ValidationLocatorLib.loadFromSignature(signature); return _isValidSignature(locator.lookupKey(), hash, signatureRemainder); } /// @inheritdoc IERC165 /// @notice ERC-165 introspection /// @dev returns true for `IERC165.interfaceId` and false for `0xFFFFFFFF` /// @param interfaceId interface id to check against /// @return bool support for specific interface function supportsInterface(bytes4 interfaceId) external view override returns (bool) { if (interfaceId == _INTERFACE_ID_INVALID) { return false; } if ( interfaceId == type(IERC721Receiver).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC165).interfaceId ) { return true; } return getAccountStorage().supportedIfaces[interfaceId] > 0; } /// @inheritdoc IModularAccount function accountId() external pure virtual returns (string memory); /// @inheritdoc UUPSUpgradeable /// @notice May be validated by a global validation. function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual override onlyProxy wrapNativeFunction { super.upgradeToAndCall(newImplementation, data); } // INTERNAL FUNCTIONS // Parent function validateUserOp enforces that this call can only be made by the EntryPoint function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) internal override returns (uint256 validationData) { ValidationLocator locator = ValidationLocatorLib.loadFromNonce(userOp.nonce); bytes calldata userOpSignature = userOp.signature; /// The calldata layout is unique for deferred validation installation. /// Byte indices are [inclusive, exclusive] and relative to the start of the signature after the locator is /// decoded and removed. /// [0:4] : uint32, encodedDatalength. /// [4:(4 + encodedDatalength)] : bytes, abi-encoded deferred action data. /// [(4 + encodedDataLength):(8 + encodedDataLength)] : uint32, deferredActionSigLength. /// [(8 + encodedDataLength):(8 + deferredActionSigLength + encodedDataLength)] : bytes, /// deferred action sig. This is the signature passed to the outer validation decoded earlier. /// [(8 + deferredActionSigLength + encodedDataLength):] : bytes, userOpSignature. This is the /// signature passed to the inner validation. if (locator.hasDeferredAction()) { // Use inner validation as a 1271 validation for the deferred action, then use the outer // validation to validate the UO. // Get the length of the deferred action data. uint256 encodedDataLength = uint32(bytes4(userOpSignature[:4])); // Load the pointer to the encoded data. bytes calldata encodedData = userOpSignature[4:4 + encodedDataLength]; // Get the deferred action signature length. uint256 deferredActionSigLength = uint32(bytes4(userOpSignature[4 + encodedDataLength:8 + encodedDataLength])); // Get the deferred installation signature, which is passed to the outer validation to handle the // deferred action. bytes calldata deferredActionSig = userOpSignature[8 + encodedDataLength:8 + encodedDataLength + deferredActionSigLength]; //Validate the signature. // Freeze the free-memory pointer, since we won't need to use anything from the deferred action // validation memory. MemSnapshot memSnapshot = MemManagementLib.freezeFMP(); uint48 deadline = _handleDeferredAction(userOp.nonce, encodedData, deferredActionSig); // Restore the free memory pointer. MemManagementLib.restoreFMP(memSnapshot); // Update the validation data with the deadline. validationData = uint256(deadline) << 160; // Update the UserOp signature to the remaining bytes. userOpSignature = userOpSignature[8 + encodedDataLength + deferredActionSigLength:]; } _checkIfValidationAppliesCallData( userOp.callData, locator.lookupKey(), locator.isGlobal() ? ValidationCheckingType.GLOBAL : ValidationCheckingType.SELECTOR ); // Check if there are execution hooks associated with the validator, and revert if the call isn't to // `executeUserOp`. This check must be here because if context isn't passed, we can't tell in execution // which hooks should have ran. if ( getAccountStorage().validationStorage[locator.lookupKey()].executionHookCount > 0 && bytes4(userOp.callData[:4]) != this.executeUserOp.selector ) { revert RequireUserOperationContext(); } uint256 userOpValidationRes = _doUserOpValidation(userOp, userOpHash, locator.lookupKey(), userOpSignature); // We only coalesce validations if the validation data from deferred installation is nonzero. if (validationData != 0) { validationData = _coalesceValidation(validationData, userOpValidationRes); } else { validationData = userOpValidationRes; } } /// @return The deadline of the deferred action function _handleDeferredAction(uint256 userOpNonce, bytes calldata encodedData, bytes calldata sig) internal returns (uint48) { // The inner validation, deadline, and deferred call bytes are all at fixed positions in the encoded data. // [:21] = ValidationLocator defActionValidationLocator // [21:27] = uint48 deadline // [27:] = bytes deferredCall ValidationLocator defActionValidationLocator = ValidationLocator.wrap(uint168(bytes21(encodedData[:21]))); ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[defActionValidationLocator.lookupKey()]; // Because this bypasses UO validation hooks, we require that the validation used does not include any // validation hooks. if (_validationStorage.validationHookCount != 0) { revert DeferredValidationHasValidationHooks(); } uint48 deadline = uint48(bytes6(encodedData[21:27])); bytes32 typedDataHash = _computeDeferredActionHash(userOpNonce, deadline, encodedData[27:]); // Check if the outer validation applies to the function call _checkIfValidationAppliesCallData( encodedData[27:], defActionValidationLocator.lookupKey(), defActionValidationLocator.isGlobal() ? ValidationCheckingType.GLOBAL : ValidationCheckingType.SELECTOR ); // Handle the signature validation _validateDeferredActionSignature(typedDataHash, sig, defActionValidationLocator.lookupKey()); // Run the validation associated execution hooks, allocating a call buffer as needed. HookConfig[] memory validationAssocExecHooks = MemManagementLib.loadExecHooks(_validationStorage); PHCallBuffer callBuffer; if (validationAssocExecHooks.length > 0) { callBuffer = ExecutionLib.allocatePreExecHookCallBuffer(encodedData[27:]); } DensePostHookData postHookData = ExecutionLib.doPreHooks(validationAssocExecHooks, callBuffer); // Perform the deferred action's self call on the account. ExecutionLib.callBubbleOnRevertTransient(address(this), 0, encodedData[27:]); // Do the cached post hooks ExecutionLib.doCachedPostHooks(postHookData); return deadline; } // To support gas estimation, we don't fail early when the failure is caused by a signature failure function _doUserOpValidation( PackedUserOperation calldata userOp, bytes32 userOpHash, ValidationLookupKey validationLookupKey, bytes calldata signature ) internal returns (uint256) { ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey]; // Do preUserOpValidation hooks HookConfig[] memory preUserOpValidationHooks = MemManagementLib.loadValidationHooks(_validationStorage); uint256 validationRes; UOCallBuffer userOpCallBuffer; if (!_validationIsNative(validationLookupKey) || preUserOpValidationHooks.length > 0) { userOpCallBuffer = ExecutionLib.allocateUserOpValidationCallBuffer(userOp, userOpHash); } bytes calldata currentSignatureSlice; for (uint256 i = preUserOpValidationHooks.length; i > 0; i) { // Decrement here, instead of in the loop body, to convert from length to an index. unchecked { --i; } (currentSignatureSlice, signature) = signature.advanceSegmentIfAtIndex(uint8(preUserOpValidationHooks.length - i - 1)); ModuleEntity uoValidationHook = preUserOpValidationHooks[i].moduleEntity(); uint256 currentValidationRes = ExecutionLib.invokeUserOpCallBuffer(userOpCallBuffer, uoValidationHook, currentSignatureSlice); if (uint160(currentValidationRes) > 1) { // If the aggregator is not 0 or 1, it is an unexpected value revert UnexpectedAggregator(uoValidationHook, address(uint160(currentValidationRes))); } validationRes = _coalescePreValidation(validationRes, currentValidationRes); } // Run the user op validation function { currentSignatureSlice = signature.getFinalSegment(); uint256 currentValidationRes = _execUserOpValidation(validationLookupKey, userOpHash, currentSignatureSlice, userOpCallBuffer); if (preUserOpValidationHooks.length != 0) { // If we have other validation data we need to coalesce with validationRes = _coalesceValidation(validationRes, currentValidationRes); } else { validationRes = currentValidationRes; } } return validationRes; } function _doRuntimeValidation( ValidationLookupKey validationLookupKey, bytes calldata callData, bytes calldata authorizationData ) internal returns (RTCallBuffer) { ValidationStorage storage _validationData = getAccountStorage().validationStorage[validationLookupKey]; // run all preRuntimeValidation hooks HookConfig[] memory preRuntimeValidationHooks = MemManagementLib.loadValidationHooks(_validationData); RTCallBuffer callBuffer; if (!_validationIsNative(validationLookupKey) || preRuntimeValidationHooks.length > 0) { callBuffer = ExecutionLib.allocateRuntimeValidationCallBuffer(callData, authorizationData); } for (uint256 i = preRuntimeValidationHooks.length; i > 0;) { // Decrement here, instead of in the loop update step, to handle the case where the length is 0. unchecked { --i; } bytes calldata currentAuthSegment; (currentAuthSegment, authorizationData) = authorizationData.advanceSegmentIfAtIndex(uint8(preRuntimeValidationHooks.length - i - 1)); ExecutionLib.invokeRuntimeCallBufferPreValidationHook( callBuffer, preRuntimeValidationHooks[i], currentAuthSegment ); } authorizationData = authorizationData.getFinalSegment(); _execRuntimeValidation(validationLookupKey, callBuffer, authorizationData); return callBuffer; } // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address newImplementation) internal override {} /** * Order of operations: * 1. Check if the sender is the entry point, the account itself, or the selector called is public. * - Yes: Return an empty array, there are no post executionHooks. * - No: Continue * 2. Check if the called selector (msg.sig) is included in the set of selectors the msg.sender can * directly call. * - Yes: Continue * - No: Revert, the caller is not allowed to call this selector * 3. If there are runtime validation hooks associated with this caller-sig combination, run them. * 4. Run the pre executionHooks associated with this caller-sig combination, and return the * post executionHooks to run later. */ function _checkPermittedCallerAndAssociatedHooks() internal returns (DensePostHookData) { AccountStorage storage _storage = getAccountStorage(); HookConfig[] memory execHooks; RTCallBuffer rtCallBuffer; // We only need to handle execution hooks when the sender is not the entry point or the account itself, // and the selector isn't public. if ( msg.sender != address(_ENTRY_POINT) && msg.sender != address(this) && !_storage.executionStorage[msg.sig].skipRuntimeValidation ) { ValidationLookupKey directCallValidationKey = ValidationLocatorLib.directCallLookupKey(msg.sender); _checkIfValidationAppliesCallData(msg.data, directCallValidationKey, ValidationCheckingType.EITHER); // Direct call is allowed, run associated execution & validation hooks // Validation hooks HookConfig[] memory preRuntimeValidationHooks = MemManagementLib.loadValidationHooks(_storage.validationStorage[directCallValidationKey]); uint256 preRuntimeValidationHooksLength = preRuntimeValidationHooks.length; if (preRuntimeValidationHooksLength > 0) { rtCallBuffer = ExecutionLib.allocateRuntimeValidationCallBuffer(msg.data, getEmptyCalldataSlice()); } for (uint256 i = preRuntimeValidationHooksLength; i > 0;) { // Decrement here, instead of in the loop body, to convert from length to an index. unchecked { --i; } ExecutionLib.invokeRuntimeCallBufferPreValidationHook( rtCallBuffer, preRuntimeValidationHooks[i], getEmptyCalldataSlice() ); } //Load all execution hooks: both associated with the selector and the validation function. execHooks = MemManagementLib.loadExecHooks( _storage.executionStorage[msg.sig], _storage.validationStorage[directCallValidationKey] ); } else { // If the sender is the entry point or the account itself, or the selector is public, this indicates // that validation was done elsewhere. We only need to run selector-associated execution hooks. execHooks = MemManagementLib.loadExecHooks(_storage.executionStorage[msg.sig]); } PHCallBuffer preHookCallBuffer; if (execHooks.length > 0) { preHookCallBuffer = ExecutionLib.convertToPreHookCallBuffer(rtCallBuffer, msg.data); } // Exec hooks associated with the selector DensePostHookData postHookData = ExecutionLib.doPreHooks(execHooks, preHookCallBuffer); return postHookData; } function _execUserOpValidation( ValidationLookupKey validationLookupKey, bytes32 hash, bytes calldata signatureSegment, UOCallBuffer callBuffer ) internal virtual returns (uint256) { (hash); // unused in ModularAccountBase, but used in SemiModularAccountBase ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey]; ModuleEntity userOpValidationFunction = validationLookupKey.moduleEntity(_validationStorage); if (!_validationStorage.validationFlags.isUserOpValidation()) { revert UserOpValidationInvalid(userOpValidationFunction); } ExecutionLib.convertToValidationBuffer(callBuffer); return ExecutionLib.invokeUserOpCallBuffer(callBuffer, userOpValidationFunction, signatureSegment); } function _execRuntimeValidation( ValidationLookupKey validationLookupKey, RTCallBuffer callBuffer, bytes calldata authorization ) internal virtual { ValidationStorage storage _validationData = getAccountStorage().validationStorage[validationLookupKey]; ModuleEntity runtimeValidationFunction = validationLookupKey.moduleEntity(_validationData); ExecutionLib.invokeRuntimeCallBufferValidation(callBuffer, runtimeValidationFunction, authorization); } function _computeDeferredActionHash(uint256 userOpNonce, uint48 deadline, bytes calldata selfCall) internal view returns (bytes32) { // Note: // - A zero deadline translates to "no deadline" // - The user op nonce also includes the data for: // - Which validation function to use // - Whether or not a deferred action is included // - Whether or not the validation is used as a global validation. // Compute the hash without permanently allocating memory for each step. // The following is equivalent to: // keccak256( // abi.encode( // _DEFERRED_ACTION_TYPEHASH, // nonce, // deadline, // keccak256(selfCall) // ) // ) // Compute the struct hash, then convert it to a typed data hash. bytes32 structHash; assembly ("memory-safe") { // Get the hash of the dynamic-length encoded install call let fmp := mload(0x40) calldatacopy(fmp, selfCall.offset, selfCall.length) let selfCallHash := keccak256(fmp, selfCall.length) // Compute the struct hash let ptr := fmp mstore(ptr, _DEFERRED_ACTION_TYPEHASH) ptr := add(ptr, 0x20) mstore(ptr, userOpNonce) ptr := add(ptr, 0x20) // Clear the upper bits of the deadline, in case the caller didn't. mstore(ptr, and(deadline, 0xffffffffffff)) ptr := add(ptr, 0x20) mstore(ptr, selfCallHash) // Compute the struct hash structHash := keccak256(fmp, 0x80) } bytes32 typedDataHash = MessageHashUtils.toTypedDataHash(_domainSeparator(), structHash); return typedDataHash; } function _validateDeferredActionSignature( bytes32 defActionTypedDataHash, bytes calldata signature, ValidationLookupKey deferredSigValidationLookupKey ) internal view { // Validate the 1271 signature. SigCallBuffer sigCallBuffer; if (!_validationIsNative(deferredSigValidationLookupKey)) { sigCallBuffer = ExecutionLib.allocateSigCallBuffer(defActionTypedDataHash, signature); } if ( _exec1271Validation(sigCallBuffer, defActionTypedDataHash, deferredSigValidationLookupKey, signature) != _1271_MAGIC_VALUE ) { revert DeferredActionSignatureInvalid(); } } function _isValidSignature(ValidationLookupKey validationLookupKey, bytes32 hash, bytes calldata signature) internal view returns (bytes4) { ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey]; HookConfig[] memory preSignatureValidationHooks = MemManagementLib.loadValidationHooks(_validationStorage); SigCallBuffer sigCallBuffer; if (!_validationIsNative(validationLookupKey) || preSignatureValidationHooks.length > 0) { sigCallBuffer = ExecutionLib.allocateSigCallBuffer(hash, signature); } for (uint256 i = preSignatureValidationHooks.length; i > 0;) { // Decrement here, instead of in the loop body, to convert from length to an index. unchecked { --i; } bytes calldata currentSignatureSegment; (currentSignatureSegment, signature) = signature.advanceSegmentIfAtIndex(uint8(preSignatureValidationHooks.length - i - 1)); ExecutionLib.invokePreSignatureValidationHook( sigCallBuffer, preSignatureValidationHooks[i], currentSignatureSegment ); } signature = signature.getFinalSegment(); return _exec1271Validation(sigCallBuffer, hash, validationLookupKey, signature); } function _exec1271Validation( SigCallBuffer buffer, bytes32 hash, ValidationLookupKey validationLookupKey, bytes calldata signatureSegment ) internal view virtual returns (bytes4) { (hash); // unused in ModularAccountBase, but used in SemiModularAccountBase ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey]; ModuleEntity sigValidation = validationLookupKey.moduleEntity(_validationStorage); if (!_validationStorage.validationFlags.isSignatureValidation()) { revert SignatureValidationInvalid(sigValidation); } if (ExecutionLib.invokeSignatureValidation(buffer, sigValidation, signatureSegment) == _1271_MAGIC_VALUE) { return _1271_MAGIC_VALUE; } return _1271_INVALID; } function _isValidationGlobal(ValidationLookupKey validationFunction) internal view virtual returns (bool) { return getAccountStorage().validationStorage[validationFunction].validationFlags.isGlobal(); } function _checkIfValidationAppliesCallData( bytes calldata callData, ValidationLookupKey validationFunction, ValidationCheckingType checkingType ) internal view { if (callData.length < 4) { revert UnrecognizedFunction(bytes4(callData)); } bytes4 outerSelector = bytes4(callData); if (outerSelector == this.executeUserOp.selector) { // If the selector is executeUserOp, pull the actual selector from the following data, // and trim the calldata to ensure the self-call decoding is still accurate. callData = callData[4:]; outerSelector = bytes4(callData[:4]); } _checkIfValidationAppliesSelector(outerSelector, validationFunction, checkingType); if (outerSelector == IModularAccount.execute.selector) { address target = MemManagementLib.getExecuteTarget(callData); if (target == address(this)) { // There is no point to call `execute` to recurse exactly once - this is equivalent to just having // the calldata as a top-level call. revert SelfCallRecursionDepthExceeded(); } } else if (outerSelector == IModularAccount.executeBatch.selector) { // executeBatch may be used to batch account actions together, by targetting the account itself. // If this is done, we must ensure all of the inner calls are allowed by the provided validation // function. _checkExecuteBatchValidationApplicability(callData[4:], validationFunction, checkingType); } } /// @notice Checks if the validation function is allowed to perform this call to `executeBatch`. /// @param callData The calldata to check, excluding the `executeBatch` selector. /// @param validationFunction The validation function to check against. /// @param checkingType The type of validation checking to perform. function _checkExecuteBatchValidationApplicability( bytes calldata callData, ValidationLookupKey validationFunction, ValidationCheckingType checkingType ) internal view { // Equivalent to the following code, but without using memory. // (Call[] memory calls) = abi.decode(callData, (Call[])); // for (uint256 i = 0; i < calls.length; ++i) { // if (calls[i].target == address(this)) { // bytes4 nestedSelector = bytes4(calls[i].data[:4]); // if ( // nestedSelector == IModularAccount.execute.selector // || nestedSelector == IModularAccount.executeBatch.selector // ) { // // revert SelfCallRecursionDepthExceeded(); // } // _checkIfValidationAppliesSelector(nestedSelector, validationFunction, checkingType); // } // } // The following is adapted from the compiler-generated ABI decoder for the `Call[] calldata` parameter // type. See test/mocks/MockDecoder.sol for more info. // This allows the decoding behavior here, in the validation step, to match what would happen during the // actual execution of `executeBatch`. // This follows the compiler-generated behavior of: // - asserting the data to load fits in the remaining space of the current `bytes calldata`. // - asserting that the ABI-encoded offsets and lengths do not exceed the constant value // 0xffffffffffffffff. // The end of allowed calldata to read. Declared in an outer context to make available to multiple code // blocks. uint256 dataEnd; // The absolute offset of the start of the `Call[]` array. uint256 arrayPos; // The length of the `Call[]` array. uint256 callsLength; // This block is retrieving the actual Call[] location and length, asserting it doesn't go out of bounds. assembly ("memory-safe") { // Set up the "safe data decoding range" let headStart := callData.offset dataEnd := add(headStart, callData.length) // Assert it is safe to load the offset if slt(sub(dataEnd, headStart), 32) { revert(0, 0) } // Load and sanitize the offset let relOffset := calldataload(callData.offset) if gt(relOffset, 0xffffffffffffffff) { revert(0, 0) } // Convert from a relative offset to an absolute offset. let absOffset := add(headStart, relOffset) // Assert it is safe to load the length if iszero(slt(add(absOffset, 0x1f), dataEnd)) { revert(0, 0) } // Load and sanitize the length callsLength := calldataload(absOffset) if gt(callsLength, 0xffffffffffffffff) { revert(0, 0) } // Load the array position, and check that it fits within the alloted length. arrayPos := add(absOffset, 0x20) if gt(add(arrayPos, mul(callsLength, 0x20)), dataEnd) { revert(0, 0) } } // Now, we have the array length and data bounds. // Iterate through the array elements, checking: // - If the target is this account, assert that: // - the selector in the data field is not `execute` or `executeBatch`. // - the provided validation is allowed to call the selector. for (uint256 i = 0; i < callsLength; ++i) { address callTarget; uint256 structAbsOffset; // This block is retrieving the actual calls[i] struct location and contents, asserting it doesn't go // out of bounds. assembly ("memory-safe") { // Load and sanitize the struct offset. // This is still safe to load, from the bounds check above. let structRelOffset := calldataload(add(arrayPos, mul(i, 0x20))) if gt(structRelOffset, 0xffffffffffffffff) { revert(0, 0) } // Validate struct offset. If the offset points to a location with < 3 words of space before the // end of data, revert. if iszero(slt(structRelOffset, sub(sub(dataEnd, arrayPos), sub(0x60, 1)))) { revert(0, 0) } structAbsOffset := add(arrayPos, structRelOffset) // Load the address from the struct, and sanitize its contents, to mirror the behavior of the ABI // decoder. callTarget := calldataload(structAbsOffset) if iszero(eq(and(callTarget, 0xffffffffffffffffffffffffffffffffffffffff), callTarget)) { revert(0, 0) } } if (callTarget == address(this)) { // In this case, we must load the selector, deny if it's `execute` or `executeBatch`, and check // validation applicability. uint32 selector; // This block is retrieving the selector from the first 4 bytes of calls[i].data, asserting it // doesn't go out of bounds and that the data is at least 4 bytes long. assembly ("memory-safe") { // Load and sanitize the data offset. let dataRelOffset := calldataload(add(structAbsOffset, 0x40)) if gt(dataRelOffset, 0xffffffffffffffff) { revert(0, 0) } // Validate data offset. If the offset points to a location with < 1 words of space before the // end of data, revert. if iszero(slt(dataRelOffset, sub(sub(dataEnd, structAbsOffset), sub(0x20, 1)))) { revert(0, 0) } let dataAbsOffset := add(structAbsOffset, dataRelOffset) // Load and sanitize the data length. let dataLength := calldataload(dataAbsOffset) if gt(dataLength, 0xffffffff) { revert(0, 0) } // Get the data offset, and assert that the following data fits into the bounded calldata // range. let dataOffset := add(dataAbsOffset, 0x20) if sgt(dataOffset, sub(dataEnd, mul(dataLength, 0x01))) { revert(0, 0) } // Finally, load the selector being called. This will be the first 4 bytes of the data. // If the data length is less than 4, revert. if slt(dataLength, 4) { revert(0, 0) } selector := shr(224, calldataload(dataOffset)) } if (selector == uint32(this.execute.selector) || selector == uint32(this.executeBatch.selector)) { // To prevent arbitrarily-deep recursive checking, we limit the depth of self-calls to one // for the purposes of batching. // This means that all self-calls must occur at the top level of the batch. // Note that modules of other contracts using `executeWithRuntimeValidation` may still // independently call into this account with a different validation function, allowing // composition of multiple batches. revert SelfCallRecursionDepthExceeded(); } _checkIfValidationAppliesSelector(bytes4(selector), validationFunction, checkingType); } } } function _checkIfValidationAppliesSelector( bytes4 selector, ValidationLookupKey validationFunction, ValidationCheckingType checkingType ) internal view { // Check that the provided validation function is applicable to the selector if (checkingType == ValidationCheckingType.GLOBAL) { if (!_globalValidationApplies(selector, validationFunction)) { revert ValidationFunctionMissing(selector); } } else if (checkingType == ValidationCheckingType.SELECTOR) { if (!_selectorValidationApplies(selector, validationFunction)) { revert ValidationFunctionMissing(selector); } } else { if ( !_globalValidationApplies(selector, validationFunction) && !_selectorValidationApplies(selector, validationFunction) ) { revert ValidationFunctionMissing(selector); } } } function _globalValidationApplies(bytes4 selector, ValidationLookupKey validationFunction) internal view returns (bool) { return _globalValidationAllowed(selector) && _isValidationGlobal(validationFunction); } function _globalValidationAllowed(bytes4 selector) internal view returns (bool) { return _isGlobalValidationAllowedNativeFunction(uint32(selector)) || getAccountStorage().executionStorage[selector].allowGlobalValidation; } function _selectorValidationApplies(bytes4 selector, ValidationLookupKey validationFunction) internal view returns (bool) { return getAccountStorage().validationStorage[validationFunction].selectors.contains(toSetValue(selector)); } function _domainSeparator() internal view returns (bytes32) { bytes32 result; // Compute the hash without permanently allocating memory assembly ("memory-safe") { let fmp := mload(0x40) mstore(fmp, _DOMAIN_SEPARATOR_TYPEHASH) mstore(add(fmp, 0x20), chainid()) mstore(add(fmp, 0x40), address()) result := keccak256(fmp, 0x60) } return result; } // A virtual function to detect if a validation function is natively implemented. Used for determining call // buffer allocation. function _validationIsNative(ValidationLookupKey) internal pure virtual returns (bool) { return false; } }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; import {IModule} from "./IModule.sol"; struct ManifestExecutionFunction { // The selector to install bytes4 executionSelector; // If true, the function won't need runtime validation, and can be called by anyone. bool skipRuntimeValidation; // If true, the function can be validated by a global validation function. bool allowGlobalValidation; } struct ManifestExecutionHook { bytes4 executionSelector; uint32 entityId; bool isPreHook; bool isPostHook; } /// @dev A struct describing how the module should be installed on a modular account. struct ExecutionManifest { // Execution functions defined in this module to be installed on the MSCA. ManifestExecutionFunction[] executionFunctions; ManifestExecutionHook[] executionHooks; // List of ERC-165 interface IDs to add to account to support introspection checks. This MUST NOT include // IModule's interface ID. bytes4[] interfaceIds; } interface IExecutionModule is IModule { /// @notice Describe the contents and intended configuration of the module. /// @dev This manifest MUST stay constant over time. /// @return A manifest describing the contents and intended configuration of the module. function executionManifest() external pure returns (ExecutionManifest memory); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; /** * User Operation struct * @param sender - The sender account of this request. * @param nonce - Unique value the sender uses to verify it is not a replay. * @param initCode - If set, the account contract will be created by this constructor/ * @param callData - The method call to execute on this account. * @param accountGasLimits - Packed gas limits for validateUserOp and gas limit passed to the callData method call. * @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid. * Covers batch overhead. * @param gasFees - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters. * @param paymasterAndData - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data * The paymaster will pay for the transaction instead of the sender. * @param signature - Sender-verified signature over the entire request, the EntryPoint address and the chain ID. */ struct PackedUserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; bytes32 accountGasLimits; uint256 preVerificationGas; bytes32 gasFees; bytes paymasterAndData; bytes signature; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.7.5; /** * Manage deposits and stakes. * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account). * Stake is value locked for at least "unstakeDelay" by the staked entity. */ interface IStakeManager { event Deposited(address indexed account, uint256 totalDeposit); event Withdrawn( address indexed account, address withdrawAddress, uint256 amount ); // Emitted when stake or unstake delay are modified. event StakeLocked( address indexed account, uint256 totalStaked, uint256 unstakeDelaySec ); // Emitted once a stake is scheduled for withdrawal. event StakeUnlocked(address indexed account, uint256 withdrawTime); event StakeWithdrawn( address indexed account, address withdrawAddress, uint256 amount ); /** * @param deposit - The entity's deposit. * @param staked - True if this entity is staked. * @param stake - Actual amount of ether staked for this entity. * @param unstakeDelaySec - Minimum delay to withdraw the stake. * @param withdrawTime - First block timestamp where 'withdrawStake' will be callable, or zero if already locked. * @dev Sizes were chosen so that deposit fits into one cell (used during handleOp) * and the rest fit into a 2nd cell (used during stake/unstake) * - 112 bit allows for 10^15 eth * - 48 bit for full timestamp * - 32 bit allows 150 years for unstake delay */ struct DepositInfo { uint256 deposit; bool staked; uint112 stake; uint32 unstakeDelaySec; uint48 withdrawTime; } // API struct used by getStakeInfo and simulateValidation. struct StakeInfo { uint256 stake; uint256 unstakeDelaySec; } /** * Get deposit info. * @param account - The account to query. * @return info - Full deposit information of given account. */ function getDepositInfo( address account ) external view returns (DepositInfo memory info); /** * Get account balance. * @param account - The account to query. * @return - The deposit (for gas payment) of the account. */ function balanceOf(address account) external view returns (uint256); /** * Add to the deposit of the given account. * @param account - The account to add to. */ function depositTo(address account) external payable; /** * Add to the account's stake - amount and delay * any pending unstake is first cancelled. * @param _unstakeDelaySec - The new lock duration before the deposit can be withdrawn. */ function addStake(uint32 _unstakeDelaySec) external payable; /** * Attempt to unlock the stake. * The value can be withdrawn (using withdrawStake) after the unstake delay. */ function unlockStake() external; /** * Withdraw from the (unlocked) stake. * Must first call unlockStake and wait for the unstakeDelay to pass. * @param withdrawAddress - The address to send withdrawn value. */ function withdrawStake(address payable withdrawAddress) external; /** * Withdraw from the deposit. * @param withdrawAddress - The address to send withdrawn value. * @param withdrawAmount - The amount to withdraw. */ function withdrawTo( address payable withdrawAddress, uint256 withdrawAmount ) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; import "./PackedUserOperation.sol"; /** * Aggregated Signatures validator. */ interface IAggregator { /** * Validate aggregated signature. * Revert if the aggregated signature does not match the given list of operations. * @param userOps - Array of UserOperations to validate the signature for. * @param signature - The aggregated signature. */ function validateSignatures( PackedUserOperation[] calldata userOps, bytes calldata signature ) external view; /** * Validate signature of a single userOp. * This method should be called by bundler after EntryPointSimulation.simulateValidation() returns * the aggregator this account uses. * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps. * @param userOp - The userOperation received from the user. * @return sigForUserOp - The value to put into the signature field of the userOp when calling handleOps. * (usually empty, unless account and aggregator support some kind of "multisig". */ function validateUserOpSignature( PackedUserOperation calldata userOp ) external view returns (bytes memory sigForUserOp); /** * Aggregate multiple signatures into a single value. * This method is called off-chain to calculate the signature to pass with handleOps() * bundler MAY use optimized custom code perform this aggregation. * @param userOps - Array of UserOperations to collect the signatures from. * @return aggregatedSignature - The aggregated signature. */ function aggregateSignatures( PackedUserOperation[] calldata userOps ) external view returns (bytes memory aggregatedSignature); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; interface INonceManager { /** * Return the next nonce for this sender. * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop) * But UserOp with different keys can come with arbitrary order. * * @param sender the account address * @param key the high 192 bit of the nonce * @return nonce a full nonce to pass for next UserOp with this sender. */ function getNonce(address sender, uint192 key) external view returns (uint256 nonce); /** * Manually increment the nonce of the sender. * This method is exposed just for completeness.. * Account does NOT need to call it, neither during validation, nor elsewhere, * as the EntryPoint will update the nonce regardless. * Possible use-case is call it with various keys to "initialize" their nonces to one, so that future * UserOperations will not pay extra for the first transaction with a given key. */ function incrementNonce(uint192 key) external; }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; interface IModule is IERC165 { /// @notice Initialize module data for the modular account. /// @dev Called by the modular account during `installExecution`. /// @param data Optional bytes array to be decoded and used by the module to setup initial module data for the /// modular account. function onInstall(bytes calldata data) external; /// @notice Clear module data for the modular account. /// @dev Called by the modular account during `uninstallExecution`. /// @param data Optional bytes array to be decoded and used by the module to clear module data for the modular /// account. function onUninstall(bytes calldata data) external; /// @notice Return a unique identifier for the module. /// @dev This function MUST return a string in the format "vendor.module.semver". The vendor and module /// names MUST NOT contain a period character. /// @return The module ID. function moduleId() external view returns (string memory); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.20; import {HookConfig, ModuleEntity} from "../interfaces/IModularAccount.sol"; // Hook types: // Exec hook: bools for hasPre, hasPost // Validation hook: no bools // Hook fields: // module address // entity ID // hook type // if exec hook: hasPre, hasPost // Hook config is a packed representation of a hook function and flags for its configuration. // Layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address // 0x________________________________________BBBBBBBB________________ // Entity ID // 0x________________________________________________CC______________ // Hook Flags // Hook flags layout: // 0b00000___ // unused // 0b_____A__ // hasPre (exec only) // 0b______B_ // hasPost (exec only) // 0b_______C // hook type (0 for exec, 1 for validation) library HookConfigLib { // Hook type constants // Exec has no bits set bytes32 internal constant _HOOK_TYPE_EXEC = bytes32(uint256(0)); // Validation has 1 in the 25th byte bytes32 internal constant _HOOK_TYPE_VALIDATION = bytes32(uint256(1) << 56); // Exec hook flags constants // Pre hook has 1 in 4's bit in the 25th byte bytes32 internal constant _EXEC_HOOK_HAS_PRE = bytes32(uint256(1) << 58); // Post hook has 1 in 2's bit in the 25th byte bytes32 internal constant _EXEC_HOOK_HAS_POST = bytes32(uint256(1) << 57); function packValidationHook(ModuleEntity _hookFunction) internal pure returns (HookConfig) { return HookConfig.wrap(bytes25(bytes25(ModuleEntity.unwrap(_hookFunction)) | bytes25(_HOOK_TYPE_VALIDATION))); } function packValidationHook(address _module, uint32 _entityId) internal pure returns (HookConfig) { return HookConfig.wrap( bytes25( // module address stored in the first 20 bytes bytes25(bytes20(_module)) // entityId stored in the 21st - 24th byte | bytes25(bytes24(uint192(_entityId))) | bytes25(_HOOK_TYPE_VALIDATION) ) ); } function packExecHook(ModuleEntity _hookFunction, bool _hasPre, bool _hasPost) internal pure returns (HookConfig) { return HookConfig.wrap( bytes25( bytes25(ModuleEntity.unwrap(_hookFunction)) // | bytes25(_HOOK_TYPE_EXEC) // Can omit because exec type is 0 | bytes25(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0)) | bytes25(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0)) ) ); } function packExecHook(address _module, uint32 _entityId, bool _hasPre, bool _hasPost) internal pure returns (HookConfig) { return HookConfig.wrap( bytes25( // module address stored in the first 20 bytes bytes25(bytes20(_module)) // entityId stored in the 21st - 24th byte | bytes25(bytes24(uint192(_entityId))) // | bytes25(_HOOK_TYPE_EXEC) // Can omit because exec type is 0 | bytes25(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0)) | bytes25(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0)) ) ); } function unpackValidationHook(HookConfig _config) internal pure returns (ModuleEntity _hookFunction) { bytes25 configBytes = HookConfig.unwrap(_config); _hookFunction = ModuleEntity.wrap(bytes24(configBytes)); } function unpackExecHook(HookConfig _config) internal pure returns (ModuleEntity _hookFunction, bool _hasPre, bool _hasPost) { bytes25 configBytes = HookConfig.unwrap(_config); _hookFunction = ModuleEntity.wrap(bytes24(configBytes)); _hasPre = configBytes & _EXEC_HOOK_HAS_PRE != 0; _hasPost = configBytes & _EXEC_HOOK_HAS_POST != 0; } function module(HookConfig _config) internal pure returns (address) { return address(bytes20(HookConfig.unwrap(_config))); } function entityId(HookConfig _config) internal pure returns (uint32) { return uint32(bytes4(HookConfig.unwrap(_config) << 160)); } function moduleEntity(HookConfig _config) internal pure returns (ModuleEntity) { return ModuleEntity.wrap(bytes24(HookConfig.unwrap(_config))); } // Check if the hook is a validation hook // If false, it is an exec hook function isValidationHook(HookConfig _config) internal pure returns (bool) { return HookConfig.unwrap(_config) & _HOOK_TYPE_VALIDATION != 0; } // Check if the exec hook has a pre hook // Undefined behavior if the hook is not an exec hook function hasPreHook(HookConfig _config) internal pure returns (bool) { return HookConfig.unwrap(_config) & _EXEC_HOOK_HAS_PRE != 0; } // Check if the exec hook has a post hook // Undefined behavior if the hook is not an exec hook function hasPostHook(HookConfig _config) internal pure returns (bool) { return HookConfig.unwrap(_config) & _EXEC_HOOK_HAS_POST != 0; } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {HookConfig, ValidationFlags} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {LinkedListSet, SetValue} from "../libraries/LinkedListSetLib.sol"; import {ValidationLookupKey} from "../libraries/ValidationLocatorLib.sol"; // ERC-7201 derived storage slot. // keccak256(abi.encode(uint256(keccak256("Alchemy.ModularAccount.Storage_V2")) - 1)) & ~bytes32(uint256(0xff)) bytes32 constant _ACCOUNT_STORAGE_SLOT = 0x596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd00; /// @notice Represents data associated with a specific function selector. struct ExecutionStorage { // The module that implements this execution function. // If this is a native function, the address should remain address(0). address module; // Whether or not the function needs runtime validation, or can be called without any validation. The function // can still be state changing if this flag is set to true. // Note that even if this is set to true, user op validation will still be required, otherwise any caller could // drain the account of native tokens by wasting gas. bool skipRuntimeValidation; // Whether or not a global validation function may be used to validate this function. bool allowGlobalValidation; // The execution hooks for this function selector. LinkedListSet executionHooks; } /// @notice Represents data associated with a specific validation function. struct ValidationStorage { // The address of the validation module. address module; // ValidationFlags layout: // 0b00000___ // unused // 0b_____A__ // isGlobal // 0b______B_ // isSignatureValidation // 0b_______C // isUserOpValidation ValidationFlags validationFlags; // Length of the validation hooks for this validation function. The length is stored here, in the same storage // slot as the flags, to save an `sload` when putting the hooks into memory. uint8 validationHookCount; // Length of execution hooks for this validation function. The length is stored here, in the same storage slot // as the flags, to save an `sload` when putting the hooks into memory. uint8 executionHookCount; // The validation hooks for this validation function. LinkedListSet validationHooks; // Execution hooks to run with this validation function. LinkedListSet executionHooks; // The set of selectors that may be validated by this validation function. LinkedListSet selectors; } /// @custom:storage-location erc7201:Alchemy.ModularAccount.Storage_V2 struct AccountStorage { // AccountStorageInitializable variables. uint64 initialized; bool initializing; // Execution functions and their associated functions. mapping(bytes4 selector => ExecutionStorage) executionStorage; // Validation functions and their associated functions. mapping(ValidationLookupKey lookupKey => ValidationStorage) validationStorage; // Module-defined ERC-165 interfaces installed on the account. mapping(bytes4 => uint256) supportedIfaces; } function getAccountStorage() pure returns (AccountStorage storage _storage) { assembly ("memory-safe") { _storage.slot := _ACCOUNT_STORAGE_SLOT } } function toSetValue(HookConfig hookConfig) pure returns (SetValue) { return SetValue.wrap(bytes31(HookConfig.unwrap(hookConfig))); } function toSetValue(bytes4 selector) pure returns (SetValue) { return SetValue.wrap(bytes31(selector)); }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol"; import {IExecutionModule} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol"; import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol"; import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol"; import {IAggregator} from "@eth-infinitism/account-abstraction/interfaces/IAggregator.sol"; import {IPaymaster} from "@eth-infinitism/account-abstraction/interfaces/IPaymaster.sol"; /// @title Known Selectors Library /// @author Alchemy /// @notice Library to help to check if a selector is an ERC-6900 module function or a an ERC-4337 contract /// function. library KnownSelectorsLib { /// @notice Check if a selector is an ERC-4337 function. /// @param selector The selector to check. /// @return True if the selector is an ERC-4337 function, false otherwise. function isERC4337Function(uint32 selector) internal pure returns (bool) { return selector == uint32(IAggregator.validateSignatures.selector) || selector == uint32(IAggregator.validateUserOpSignature.selector) || selector == uint32(IAggregator.aggregateSignatures.selector) || selector == uint32(IPaymaster.validatePaymasterUserOp.selector) || selector == uint32(IPaymaster.postOp.selector); } /// @notice Check if a selector is an ERC-6900 module function. /// @param selector The selector to check. /// @return True if the selector is an ERC-6900 module function, false otherwise. function isIModuleFunction(uint32 selector) internal pure returns (bool) { return selector == uint32(IModule.onInstall.selector) || selector == uint32(IModule.onUninstall.selector) || selector == uint32(IModule.moduleId.selector) || selector == uint32(IExecutionModule.executionManifest.selector) || selector == uint32(IExecutionHookModule.preExecutionHook.selector) || selector == uint32(IExecutionHookModule.postExecutionHook.selector) || selector == uint32(IValidationModule.validateUserOp.selector) || selector == uint32(IValidationModule.validateRuntime.selector) || selector == uint32(IValidationModule.validateSignature.selector) || selector == uint32(IValidationHookModule.preUserOpValidationHook.selector) || selector == uint32(IValidationHookModule.preRuntimeValidationHook.selector) || selector == uint32(IValidationHookModule.preSignatureValidationHook.selector); } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; type SetValue is bytes31; /// @dev The sentinel value is used to indicate the head and tail of the list. bytes32 constant SENTINEL_VALUE = bytes32(uint256(1)); struct LinkedListSet { // Byte Layout // | value | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__ | // | meta | 0x______________________________________________________________BB | // Bit-layout of the meta byte // | unused | 0b0000000_ | // | sentinel | 0b_______A | // Key excludes the meta bytes, except for the sentinel value, which is 0x1 mapping(bytes32 => bytes32) map; } /// @title Linked List Set Library /// @author Alchemy /// @notice This library provides a set of functions for managing enumerable sets of bytes31 values. It is a fork /// of the LinkedListSet library in modular-account-libs, with the following changes: /// - The flags feature has been removed, so the library no longer supports both the "has next" flag, and the /// user-defined flags. /// - The library has been modified to work with bytes31 values instead of bytes30 values. library LinkedListSetLib { /// @notice Add a value to a set. /// @param set The set to add the value to. /// @param value The value to add. /// @return True if the value was added, false if the value cannot be added (already exists or is zero). function tryAdd(LinkedListSet storage set, SetValue value) internal returns (bool) { mapping(bytes32 => bytes32) storage map = set.map; bytes32 unwrappedKey = SetValue.unwrap(value); if (unwrappedKey == bytes32(0) || map[unwrappedKey] != bytes32(0)) return false; bytes32 prev = map[SENTINEL_VALUE]; if (prev == bytes32(0) || isSentinel(prev)) { // Set is empty map[SENTINEL_VALUE] = unwrappedKey; map[unwrappedKey] = SENTINEL_VALUE; } else { // set is not empty map[SENTINEL_VALUE] = unwrappedKey; map[unwrappedKey] = prev; } return true; } /// @notice Remove a value from a set. /// @dev This is an O(n) operation, where n is the number of elements in the set. /// @param set The set to remove the value from. /// @param value The value to remove. /// @return True if the value was removed, false if the value does not exist. function tryRemove(LinkedListSet storage set, SetValue value) internal returns (bool) { mapping(bytes32 => bytes32) storage map = set.map; bytes32 unwrappedKey = SetValue.unwrap(value); bytes32 nextValue = map[unwrappedKey]; if (unwrappedKey == bytes32(0) || nextValue == bytes32(0)) return false; bytes32 prevKey = SENTINEL_VALUE; bytes32 currentKey; do { currentKey = map[prevKey]; if (currentKey == unwrappedKey) { // Set the previous value's next value to the next value, // and the flags to the current value's flags. // and the next value's `hasNext` flag to determine whether or not the next value is (or points to) // the sentinel value. map[prevKey] = nextValue; map[currentKey] = bytes32(0); return true; } prevKey = currentKey; } while (!isSentinel(currentKey) && currentKey != bytes32(0)); return false; } /// @notice Remove a value from a set, given the previous value in the set. /// @dev This is an O(1) operation but requires additional knowledge. /// @param set The set to remove the value from. /// @param value The value to remove. /// @param prev The previous value in the set. /// @return True if the value was removed, false if the value does not exist, or if the wrong prev was /// specified. function tryRemoveKnown(LinkedListSet storage set, SetValue value, bytes32 prev) internal returns (bool) { mapping(bytes32 => bytes32) storage map = set.map; bytes32 unwrappedKey = SetValue.unwrap(value); if (prev == bytes32(0) || unwrappedKey == bytes32(0)) { return false; } // assert that the previous value's next value is the value to be removed bytes32 currentValue = map[prev]; if (currentValue != unwrappedKey) { return false; } bytes32 next = map[unwrappedKey]; if (next == bytes32(0)) { // The set didn't actually contain the value return false; } map[prev] = next; map[unwrappedKey] = bytes32(0); return true; } /// @notice Remove all values from a set. /// @dev This is an O(n) operation, where n is the number of elements in the set. /// @param set The set to remove the values from. function clear(LinkedListSet storage set) internal { mapping(bytes32 => bytes32) storage map = set.map; bytes32 cursor = SENTINEL_VALUE; do { bytes32 next = map[cursor]; map[cursor] = bytes32(0); cursor = next; } while (!isSentinel(cursor) && cursor != bytes32(0)); } /// @notice Check if a set contains a value. /// @dev This method does not clear the upper bits of `value`, that is expected to be done as part of casting /// to the correct type. If this function is provided the sentinel value by using the upper bits, this function /// may returns `true`. /// @param set The set to check. /// @param value The value to check for. /// @return True if the set contains the value, false otherwise. function contains(LinkedListSet storage set, SetValue value) internal view returns (bool) { mapping(bytes32 => bytes32) storage map = set.map; return map[SetValue.unwrap(value)] != bytes32(0); } /// @notice Check if a set is empty. /// @param set The set to check. /// @return True if the set is empty, false otherwise. function isEmpty(LinkedListSet storage set) internal view returns (bool) { mapping(bytes32 => bytes32) storage map = set.map; bytes32 val = map[SENTINEL_VALUE]; return val == bytes32(0) || isSentinel(val); // either the sentinel is unset, or points to itself } /// @notice Get all elements in a set. /// @dev This is an O(n) operation, where n is the number of elements in the set. /// @param set The set to get the elements of. /// @return ret An array of all elements in the set. function getAll(LinkedListSet storage set) internal view returns (SetValue[] memory ret) { mapping(bytes32 => bytes32) storage map = set.map; uint256 size; bytes32 cursor = map[SENTINEL_VALUE]; // Dynamically allocate the returned array as we iterate through the set, since we don't know the size // beforehand. // This is accomplished by first writing to memory after the free memory pointer, // then updating the free memory pointer to cover the newly-allocated data. // To the compiler, writes to memory after the free memory pointer are considered "memory safe". // See https://docs.soliditylang.org/en/v0.8.22/assembly.html#memory-safety // Stack variable lifting done when compiling with via-ir will only ever place variables into memory // locations below the current free memory pointer, so it is safe to compile this library with via-ir. // See https://docs.soliditylang.org/en/v0.8.22/yul.html#memoryguard assembly ("memory-safe") { // It is critical that no other memory allocations occur between: // - loading the value of the free memory pointer into `ret` // - updating the free memory pointer to point to the newly-allocated data, which is done after all // the values have been written. ret := mload(0x40) } while (!isSentinel(cursor) && cursor != bytes32(0)) { unchecked { ++size; } // Place the item into the return array manually. Since the size was just incremented, it will point to // the next location to write to. assembly ("memory-safe") { mstore(add(ret, mul(size, 0x20)), cursor) } cursor = map[cursor]; } assembly ("memory-safe") { // Update the free memory pointer with the now-known length of the array. mstore(0x40, add(ret, mul(add(size, 1), 0x20))) // Set the length of the array. mstore(ret, size) } } function isSentinel(bytes32 value) internal pure returns (bool ret) { assembly ("memory-safe") { ret := and(value, 1) } } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {HookConfig} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import {toSetValue} from "../account/AccountStorage.sol"; import {ExecutionLib} from "./ExecutionLib.sol"; import {LinkedListSet, LinkedListSetLib} from "./LinkedListSetLib.sol"; /// @title Module Install Commons Library /// @author Alchemy /// @notice This is an internal library which holds module installation-related functions relevant to both the /// ExecutionInstallDelegate and the ModuleManagerInternals contracts. library ModuleInstallCommonsLib { using LinkedListSetLib for LinkedListSet; error InterfaceNotSupported(address module); error ModuleInstallCallbackFailed(address module, bytes revertReason); error ExecutionHookAlreadySet(HookConfig hookConfig); // Internal Functions // We don't need to bring the exec hook removal function here since it's only ever used in the // ExecutionInstallLib /// @dev adds an execution hook to a specific set of hooks. function addExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) internal { if (!hooks.tryAdd(toSetValue(hookConfig))) { revert ExecutionHookAlreadySet(hookConfig); } } /// @dev setup the module storage for the account, reverts are bubbled up into a custom /// ModuleInstallCallbackFailed function onInstall(address module, bytes calldata data, bytes4 interfaceId) internal { if (data.length > 0) { if (!ERC165Checker.supportsERC165InterfaceUnchecked(module, interfaceId)) { revert InterfaceNotSupported(module); } // solhint-disable-next-line no-empty-blocks try IModule(module).onInstall(data) {} catch { bytes memory revertReason = ExecutionLib.collectReturnData(); revert ModuleInstallCallbackFailed(module, revertReason); } } } /// @dev clear the module storage for the account, reverts are IGNORED. Status is included in emitted event. function onUninstall(address module, bytes calldata data) internal returns (bool onUninstallSuccess) { onUninstallSuccess = true; if (data.length > 0) { // Clear the module storage for the account. // solhint-disable-next-line no-empty-blocks try IModule(module).onUninstall(data) {} catch { onUninstallSuccess = false; } } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.20; function getEmptyCalldataSlice() pure returns (bytes calldata) { bytes calldata empty; assembly ("memory-safe") { empty.length := 0 } return empty; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.20; import {ModuleEntity} from "../interfaces/IModularAccount.sol"; // ModuleEntity is a packed representation of a module function // Layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address // 0x________________________________________BBBBBBBB________________ // Entity ID // 0x________________________________________________0000000000000000 // unused library ModuleEntityLib { function pack(address addr, uint32 entityId) internal pure returns (ModuleEntity) { return ModuleEntity.wrap(bytes24(bytes20(addr)) | bytes24(uint192(entityId))); } function unpack(ModuleEntity moduleEntity) internal pure returns (address addr, uint32 entityId) { bytes24 underlying = ModuleEntity.unwrap(moduleEntity); addr = address(bytes20(underlying)); entityId = uint32(bytes4(underlying << 160)); } function isEmpty(ModuleEntity moduleEntity) internal pure returns (bool) { return ModuleEntity.unwrap(moduleEntity) == bytes24(0); } function notEmpty(ModuleEntity moduleEntity) internal pure returns (bool) { return ModuleEntity.unwrap(moduleEntity) != bytes24(0); } function eq(ModuleEntity a, ModuleEntity b) internal pure returns (bool) { return ModuleEntity.unwrap(a) == ModuleEntity.unwrap(b); } function notEq(ModuleEntity a, ModuleEntity b) internal pure returns (bool) { return ModuleEntity.unwrap(a) != ModuleEntity.unwrap(b); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.20; import {RESERVED_VALIDATION_DATA_INDEX} from "../helpers/Constants.sol"; import {getEmptyCalldataSlice} from "../helpers/EmptyCalldataSlice.sol"; /// @title Sparse Calldata Segment Library /// @notice Library for working with sparsely-packed calldata segments, identified with an index. /// @dev The first byte of each segment is the index of the segment. /// To prevent accidental stack-to-deep errors, the body and index of the segment are extracted separately, rather /// than inline as part of the tuple returned by `getNextSegment`. library SparseCalldataSegmentLib { error NonCanonicalEncoding(); error SegmentOutOfOrder(); error ValidationSignatureSegmentMissing(); /// @notice Splits out a segment of calldata, sparsely-packed. /// The expected format is: /// [uint8(index0), uint32(len(segment0)), segment0, uint8(index1), uint32(len(segment1)), segment1, /// ... uint8(indexN), uint32(len(segmentN)), segmentN] /// @param source The calldata to extract the segment from. /// @return segment The extracted segment. Using the above example, this would be segment0. /// @return remainder The remaining calldata. Using the above example, /// this would start at uint8(index1) and continue to the end at segmentN. function getNextSegment(bytes calldata source) internal pure returns (bytes calldata segment, bytes calldata remainder) { // The first byte of the segment is the index. // The next 4 bytes hold the length of the segment, excluding the index. uint32 length = uint32(bytes4(source[1:5])); // The offset of the remainder of the calldata. uint256 remainderOffset = 5 + length; // The segment is the next `length` bytes after the first 5 bytes. segment = source[5:remainderOffset]; // The remainder is the rest of the calldata. remainder = source[remainderOffset:]; } /// @notice If the index of the next segment in the source equals the provided index, return the next body and /// advance the source by one segment. /// @dev Reverts if the index of the next segment is less than the provided index, or if the extracted segment /// has length 0. /// @param source The calldata to extract the segment from. /// @param index The index of the segment to extract. /// @return A tuple containing the extracted segment's body, or an empty buffer if the index is not found, and /// the remaining calldata. function advanceSegmentIfAtIndex(bytes calldata source, uint8 index) internal pure returns (bytes calldata, bytes calldata) { uint8 nextIndex = getIndex(source); if (nextIndex < index) { revert SegmentOutOfOrder(); } if (nextIndex == index) { (bytes calldata segment, bytes calldata remainder) = getNextSegment(source); if (segment.length == 0) { revert NonCanonicalEncoding(); } return (segment, remainder); } return (getEmptyCalldataSlice(), source); } /// @notice Extracts the final segment from the source. /// @dev Reverts if the index of the segment is not RESERVED_VALIDATION_DATA_INDEX. /// @param source The calldata to extract the segment from. /// @return The final segment. function getFinalSegment(bytes calldata source) internal pure returns (bytes calldata) { if (getIndex(source) != RESERVED_VALIDATION_DATA_INDEX) { revert ValidationSignatureSegmentMissing(); } return source[1:]; } /// @notice Extracts the index from a segment. /// @dev The first byte of the segment is the index. /// @param segment The segment to extract the index from /// @return The index of the segment function getIndex(bytes calldata segment) internal pure returns (uint8) { return uint8(segment[0]); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.20; import {ModuleEntity, ValidationConfig, ValidationFlags} from "../interfaces/IModularAccount.sol"; // Validation config is a packed representation of a validation function and flags for its configuration. // Layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address // 0x________________________________________BBBBBBBB________________ // Entity ID // 0x________________________________________________CC______________ // ValidationFlags // 0x__________________________________________________00000000000000 // unused // ValidationFlags layout: // 0b00000___ // unused // 0b_____A__ // isGlobal // 0b______B_ // isSignatureValidation // 0b_______C // isUserOpValidation library ValidationConfigLib { // is user op validation flag stored in last bit of the 25th byte bytes32 internal constant _VALIDATION_FLAG_IS_USER_OP = bytes32(uint256(1) << 56); // is signature validation flag stored in second to last bit of the 25th byte bytes32 internal constant _VALIDATION_FLAG_IS_SIGNATURE = bytes32(uint256(1) << 57); // is global flag stored in the third to last bit of the 25th byte bytes32 internal constant _VALIDATION_FLAG_IS_GLOBAL = bytes32(uint256(1) << 58); function pack( ModuleEntity _validationFunction, bool _isGlobal, bool _isSignatureValidation, bool _isUserOpValidation ) internal pure returns (ValidationConfig) { return ValidationConfig.wrap( bytes25( bytes25(ModuleEntity.unwrap(_validationFunction)) | bytes25(bytes32(_isGlobal ? _VALIDATION_FLAG_IS_GLOBAL : bytes32(0))) | bytes25(bytes32(_isSignatureValidation ? _VALIDATION_FLAG_IS_SIGNATURE : bytes32(0))) | bytes25(bytes32(_isUserOpValidation ? _VALIDATION_FLAG_IS_USER_OP : bytes32(0))) ) ); } function pack( address _module, uint32 _entityId, bool _isGlobal, bool _isSignatureValidation, bool _isUserOpValidation ) internal pure returns (ValidationConfig) { return ValidationConfig.wrap( bytes25( // module address stored in the first 20 bytes bytes25(bytes20(_module)) // entityId stored in the 21st - 24th byte | bytes25(bytes24(uint192(_entityId))) | bytes25(bytes32(_isGlobal ? _VALIDATION_FLAG_IS_GLOBAL : bytes32(0))) | bytes25(bytes32(_isSignatureValidation ? _VALIDATION_FLAG_IS_SIGNATURE : bytes32(0))) | bytes25(bytes32(_isUserOpValidation ? _VALIDATION_FLAG_IS_USER_OP : bytes32(0))) ) ); } function unpackUnderlying(ValidationConfig config) internal pure returns (address _module, uint32 _entityId, ValidationFlags flags) { bytes25 configBytes = ValidationConfig.unwrap(config); _module = address(bytes20(configBytes)); _entityId = uint32(bytes4(configBytes << 160)); flags = ValidationFlags.wrap(uint8(configBytes[24])); } function unpack(ValidationConfig config) internal pure returns (ModuleEntity _validationFunction, ValidationFlags flags) { bytes25 configBytes = ValidationConfig.unwrap(config); _validationFunction = ModuleEntity.wrap(bytes24(configBytes)); flags = ValidationFlags.wrap(uint8(configBytes[24])); } function module(ValidationConfig config) internal pure returns (address) { return address(bytes20(ValidationConfig.unwrap(config))); } function entityId(ValidationConfig config) internal pure returns (uint32) { return uint32(bytes4(ValidationConfig.unwrap(config) << 160)); } function moduleEntity(ValidationConfig config) internal pure returns (ModuleEntity) { return ModuleEntity.wrap(bytes24(ValidationConfig.unwrap(config))); } function isGlobal(ValidationConfig config) internal pure returns (bool) { return ValidationConfig.unwrap(config) & _VALIDATION_FLAG_IS_GLOBAL != 0; } function isGlobal(ValidationFlags flags) internal pure returns (bool) { return ValidationFlags.unwrap(flags) & 0x04 != 0; } function isSignatureValidation(ValidationConfig config) internal pure returns (bool) { return ValidationConfig.unwrap(config) & _VALIDATION_FLAG_IS_SIGNATURE != 0; } function isSignatureValidation(ValidationFlags flags) internal pure returns (bool) { return ValidationFlags.unwrap(flags) & 0x02 != 0; } function isUserOpValidation(ValidationConfig config) internal pure returns (bool) { return ValidationConfig.unwrap(config) & _VALIDATION_FLAG_IS_USER_OP != 0; } function isUserOpValidation(ValidationFlags flags) internal pure returns (bool) { return ValidationFlags.unwrap(flags) & 0x01 != 0; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; import "./PackedUserOperation.sol"; interface IAccountExecute { /** * Account may implement this execute method. * passing this methodSig at the beginning of callData will cause the entryPoint to pass the full UserOp (and hash) * to the account. * The account should skip the methodSig, and use the callData (and optionally, other UserOp fields) * * @param userOp - The operation that was just validated. * @param userOpHash - Hash of the user's request data. */ function executeUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice UUPS proxy mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/UUPSUpgradeable.sol) /// @author Modified from OpenZeppelin /// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol) /// /// @dev Note: /// - This implementation is intended to be used with ERC1967 proxies. /// See: `LibClone.deployERC1967` and related functions. /// - This implementation is NOT compatible with legacy OpenZeppelin proxies /// which do not store the implementation at `_ERC1967_IMPLEMENTATION_SLOT`. abstract contract UUPSUpgradeable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The upgrade failed. error UpgradeFailed(); /// @dev The call is from an unauthorized call context. error UnauthorizedCallContext(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev For checking if the context is a delegate call. uint256 private immutable __self = uint256(uint160(address(this))); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when the proxy's implementation is upgraded. event Upgraded(address indexed implementation); /// @dev `keccak256(bytes("Upgraded(address)"))`. uint256 private constant _UPGRADED_EVENT_SIGNATURE = 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ERC-1967 storage slot for the implementation in the proxy. /// `uint256(keccak256("eip1967.proxy.implementation")) - 1`. bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UUPS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Please override this function to check if `msg.sender` is authorized /// to upgrade the proxy to `newImplementation`, reverting if not. /// ``` /// function _authorizeUpgrade(address) internal override onlyOwner {} /// ``` function _authorizeUpgrade(address newImplementation) internal virtual; /// @dev Returns the storage slot used by the implementation, /// as specified in [ERC1822](https://eips.ethereum.org/EIPS/eip-1822). /// /// Note: The `notDelegated` modifier prevents accidental upgrades to /// an implementation that is a proxy contract. function proxiableUUID() public view virtual notDelegated returns (bytes32) { // This function must always return `_ERC1967_IMPLEMENTATION_SLOT` to comply with ERC1967. return _ERC1967_IMPLEMENTATION_SLOT; } /// @dev Upgrades the proxy's implementation to `newImplementation`. /// Emits a {Upgraded} event. /// /// Note: Passing in empty `data` skips the delegatecall to `newImplementation`. function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); /// @solidity memory-safe-assembly assembly { newImplementation := shr(96, shl(96, newImplementation)) // Clears upper 96 bits. mstore(0x01, 0x52d1902d) // `proxiableUUID()`. let s := _ERC1967_IMPLEMENTATION_SLOT // Check if `newImplementation` implements `proxiableUUID` correctly. if iszero(eq(mload(staticcall(gas(), newImplementation, 0x1d, 0x04, 0x01, 0x20)), s)) { mstore(0x01, 0x55299b49) // `UpgradeFailed()`. revert(0x1d, 0x04) } // Emit the {Upgraded} event. log2(codesize(), 0x00, _UPGRADED_EVENT_SIGNATURE, newImplementation) sstore(s, newImplementation) // Updates the implementation. // Perform a delegatecall to `newImplementation` if `data` is non-empty. if data.length { // Forwards the `data` to `newImplementation` via delegatecall. let m := mload(0x40) calldatacopy(m, data.offset, data.length) if iszero(delegatecall(gas(), newImplementation, m, data.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } } } /// @dev Requires that the execution is performed through a proxy. modifier onlyProxy() { uint256 s = __self; /// @solidity memory-safe-assembly assembly { // To enable use cases with an immutable default implementation in the bytecode, // (see: ERC6551Proxy), we don't require that the proxy address must match the // value stored in the implementation slot, which may not be initialized. if eq(s, address()) { mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`. revert(0x1c, 0x04) } } _; } /// @dev Requires that the execution is NOT performed via delegatecall. /// This is the opposite of `onlyProxy`. modifier notDelegated() { uint256 s = __self; /// @solidity memory-safe-assembly assembly { if iszero(eq(s, address())) { mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`. revert(0x1c, 0x04) } } _; } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; // solhint-disable-next-line private-vars-leading-underscore function _coalescePreValidation(uint256 validationRes1, uint256 validationRes2) pure returns (uint256 resValidationData) { resValidationData = _coalesceValidationResTime(validationRes1, validationRes2); // Once we know that the authorizer field is 0 or 1, we can safely bubble up SIG_FAIL with bitwise OR resValidationData |= uint160(validationRes1) | uint160(validationRes2); } // solhint-disable-next-line private-vars-leading-underscore function _coalesceValidation(uint256 preValidationData, uint256 validationRes) pure returns (uint256 resValidationData) { resValidationData = _coalesceValidationResTime(preValidationData, validationRes); // If prevalidation failed, bubble up failure, and ignore authorizer resValidationData |= uint160(preValidationData) == 1 ? 1 : uint160(validationRes); } // solhint-disable-next-line private-vars-leading-underscore function _coalesceValidationResTime(uint256 validationRes1, uint256 validationRes2) pure returns (uint256 resValidationData) { uint48 validUntil1 = uint48(validationRes1 >> 160); if (validUntil1 == 0) { validUntil1 = type(uint48).max; } uint48 validUntil2 = uint48(validationRes2 >> 160); if (validUntil2 == 0) { validUntil2 = type(uint48).max; } resValidationData = ((validUntil1 > validUntil2) ? uint256(validUntil2) << 160 : uint256(validUntil1) << 160); uint48 validAfter1 = uint48(validationRes1 >> 208); uint48 validAfter2 = uint48(validationRes2 >> 208); resValidationData |= ((validAfter1 < validAfter2) ? uint256(validAfter2) << 208 : uint256(validAfter1) << 208); }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; interface IModularAccountBase { /// @notice Create a contract. /// @param value The value to send to the new contract constructor /// @param initCode The initCode to deploy. /// @param isCreate2 The bool to indicate which method to use to deploy. /// @param salt The salt for deployment. /// @return createdAddr The created contract address. function performCreate(uint256 value, bytes calldata initCode, bool isCreate2, bytes32 salt) external payable returns (address createdAddr); }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol"; import {HookConfig} from "@erc6900/reference-implementation/interfaces/IModularAccountView.sol"; import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol"; import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol"; import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol"; import {ModuleEntity} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol"; import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol"; // The following types alias a `bytes memory`, to protect the user from doing anything unexpected with it. We can't // actually alias a `bytes memory` type, so we use a `bytes32` type instead, and cast it to `bytes memory` within // this library. type UOCallBuffer is bytes32; type RTCallBuffer is bytes32; type PHCallBuffer is bytes32; type SigCallBuffer is bytes32; type DensePostHookData is bytes32; using HookConfigLib for HookConfig; /// @title Execution Library /// @author Alchemy /// @notice A library for performing external calls. This library is used for the external calls of `execute` and /// `executeBatch`, for any account self-calls, and for any call to a module function. /// @dev This library uses "call buffers", or reusable memory buffers that hold the abi-encoded data to be sent to /// a module function. These buffers are used to avoid the overhead of encoding the same data multiple times. library ExecutionLib { // solhint-disable ordering // Functions are more readable in original order. error PostExecHookReverted(ModuleEntity moduleFunction, bytes revertReason); error PreExecHookReverted(ModuleEntity moduleFunction, bytes revertReason); error PreRuntimeValidationHookReverted(ModuleEntity moduleFunction, bytes revertReason); error PreSignatureValidationHookReverted(ModuleEntity moduleFunction, bytes revertReason); error PreUserOpValidationHookReverted(ModuleEntity moduleFunction, bytes revertReason); error RuntimeValidationFunctionReverted(ModuleEntity moduleFunction, bytes revertReason); error SignatureValidationFunctionReverted(ModuleEntity moduleFunction, bytes revertReason); error UserOpValidationFunctionReverted(ModuleEntity moduleFunction, bytes revertReason); /// @notice Perform the following call, without capturing any return data. /// If the call reverts, the revert message will be directly bubbled up. /// @param target The address to call. /// @param value The value to send with the call. /// @param callData The data to send with the call. function callBubbleOnRevert(address target, uint256 value, bytes memory callData) internal { // Manually call, without collecting return data unless there's a revert. assembly ("memory-safe") { let success := call( gas(), target, /*value*/ value, /*argOffset*/ add(callData, 0x20), /*argSize*/ mload(callData), /*retOffset*/ codesize(), /*retSize*/ 0 ) // directly bubble up revert messages, if any. if iszero(success) { // For memory safety, copy this revert data to scratch space past the end of used memory. Because // we immediately revert, we can omit storing the length as we normally would for a `bytes memory` // type, as well as omit finalizing the allocation by updating the free memory pointer. let revertDataLocation := mload(0x40) returndatacopy(revertDataLocation, 0, returndatasize()) revert(revertDataLocation, returndatasize()) } } } /// @notice Transiently copy the call data to a memory, and perform a self-call. /// If the call reverts, the revert message will be directly bubbled up. /// @param target The address to call. /// @param value The value to send with the call. /// @param callData The data to send with the call. function callBubbleOnRevertTransient(address target, uint256 value, bytes calldata callData) internal { bytes memory encodedCall; assembly ("memory-safe") { // Store the length of the call encodedCall := mload(0x40) mstore(encodedCall, callData.length) // Copy in the calldata calldatacopy(add(encodedCall, 0x20), callData.offset, callData.length) } callBubbleOnRevert(target, value, encodedCall); // Memory is discarded afterwards } // Transiently copy the call data to a memory, and perform a self-call. function delegatecallBubbleOnRevertTransient(address target) internal { assembly ("memory-safe") { // Store the length of the call let fmp := mload(0x40) // Copy in the entire calldata calldatacopy(fmp, 0, calldatasize()) let success := delegatecall( gas(), target, /*argOffset*/ fmp, /*argSize*/ calldatasize(), /*retOffset*/ codesize(), /*retSize*/ 0 ) // directly bubble up revert messages, if any. if iszero(success) { // For memory safety, copy this revert data to scratch space past the end of used memory. Because // we immediately revert, we can omit storing the length as we normally would for a `bytes memory` // type, as well as omit finalizing the allocation by updating the free memory pointer. let revertDataLocation := mload(0x40) returndatacopy(revertDataLocation, 0, returndatasize()) revert(revertDataLocation, returndatasize()) } } // Memory is discarded afterwards } /// @notice Manually collect and store the return data from the most recent external call into a `bytes /// memory`. /// @return returnData The return data from the most recent external call. function collectReturnData() internal pure returns (bytes memory returnData) { assembly ("memory-safe") { // Allocate a buffer of that size, advancing the memory pointer to the nearest word returnData := mload(0x40) mstore(returnData, returndatasize()) mstore(0x40, and(add(add(returnData, returndatasize()), 0x3f), not(0x1f))) // Copy over the return data returndatacopy(add(returnData, 0x20), 0, returndatasize()) } } // Allocate a buffer to call user op validation and validation hook functions. Both of these take the form of // - bytes4 selector // - uint32 entityId // - PackedUserOperation userOp // - bytes32 userOpHash // The buffer starts with the selector for `preUserOpValidationHook`, and can be updated later to // `validateUserOp`. When perfomring the actual function calls later, update the entityId field and selector, // as as needed. function allocateUserOpValidationCallBuffer(PackedUserOperation calldata userOp, bytes32 userOpHash) internal pure returns (UOCallBuffer result) { bytes memory buffer = abi.encodeCall(IValidationHookModule.preUserOpValidationHook, (uint32(0), userOp, userOpHash)); assembly ("memory-safe") { result := buffer } // Buffer contents: // 0xAAAAAAAA // selector // 0x000: 0x________________________________________________________BBBBBBBB // entityId // 0x020: 0x______________________________________________________________60 // userOp offset // 0x040: 0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // userOp hash // 0x060: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // userOp sender // 0x080: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE // userOp nonce // 0x0a0: 0x_____________________________________________________________FFF // userOp initCode offset // 0x0c0: 0x_____________________________________________________________GGG // userOp callData offset // 0x0e0: 0xHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH // userOp accountGasLimits // 0x100: 0xIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII // userOp preVerificationGas // 0x120: 0xJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ // userOp gasFees // 0x140: 0x_____________________________________________________________KKK // userOp pmData offset // 0x160: 0x_____________________________________________________________LLL // userOp signature offset // 0x180... // dynamic fields } // Converts a user op call buffer from pre user op validation hooks to user op validation. // Performs this by writing over the selector stored in the buffer. function convertToValidationBuffer(UOCallBuffer buffer) internal pure { // Selector is treated as a uint32 to be right-aligned in the word. uint32 selector = uint32(IValidationModule.validateUserOp.selector); assembly ("memory-safe") { // We want to write in the selector without writing over anything else in the buffer, so we save the // length, write over a portion of the length, and restore it. let bufferLength := mload(buffer) mstore(add(buffer, 4), selector) mstore(buffer, bufferLength) } } // Invokes either a user op validation hook, or validation function. function invokeUserOpCallBuffer( UOCallBuffer buffer, ModuleEntity moduleEntity, bytes calldata signatureSegment ) internal returns (uint256 validationData) { bool success; address moduleAddress; uint32 entityId; assembly ("memory-safe") { // Load the module address and entity Id entityId := and(shr(64, moduleEntity), 0xffffffff) moduleAddress := shr(96, moduleEntity) // Update the buffer with the entity Id mstore(add(buffer, 0x24), entityId) // Get the offset of the user op signature in the buffer. // The PackedUserOperation starts at the 5th word in the buffer (0x20 * 4 = 0x80). // It is the 9th element in PackedUserOp (so add 0x20 * 8 = 0x100 to the buffer start). // So we start at 0x184, to include the selector length. // Then, to convert from a relative to an absolute offset, we need to add the buffer start, selector, // and to skip over the entityId, offset, and hash. let userOpSigRelativeOffset := mload(add(buffer, 0x184)) let userOpSigAbsOffset := add(add(buffer, userOpSigRelativeOffset), 0x84) // Copy in the signature segment // Since the buffer's copy of the signature exceeds the length of any sub-segments, we can safely write // over it. mstore(userOpSigAbsOffset, signatureSegment.length) // If there is a nonzero signature segment length, copy in the data. if signatureSegment.length { // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need // to zero out the last word of the buffer to prevent sending garbage data. let roundedDownSignatureLength := and(signatureSegment.length, not(0x1f)) mstore(add(userOpSigAbsOffset, add(roundedDownSignatureLength, 0x20)), 0) calldatacopy(add(userOpSigAbsOffset, 0x20), signatureSegment.offset, signatureSegment.length) } // The data amount we actually want to call with is: // buffer length - word-align(oldSignature length) + word-align(newSignature length) // Which is equivalent to: // 4 (selector length) + 0x80 (entityId, user op offset, user op hash, signature length field) // + userOpSigRelativeOffset + word-align(newSignature length) let actualCallLength := add(userOpSigRelativeOffset, 0x84) // Add in the new signature length, with word alignment. This is safe to do because the signature // segment length is guaranteed to be less than the size of the previous entire signature length. actualCallLength := add(actualCallLength, and(add(signatureSegment.length, 0x1f), not(0x1f))) // Perform the call, reverting on failure or insufficient return data. success := and( // Yul evaluates expressions from right to left, so `returndatasize` will evaluate after `call`. gt(returndatasize(), 0x1f), call( // If gas is the leftmost item before the call, it *should* be placed immediately before the // call opcode and be allowed in validation. gas(), moduleAddress, /*value*/ 0, /*argOffset*/ add(buffer, 0x20), // jump over 32 bytes for length /*argSize*/ actualCallLength, /*retOffset*/ 0, /*retSize*/ 0x20 ) ) } if (success) { assembly ("memory-safe") { // If the call was successful, we return the first word of the return data as the validation data. validationData := mload(0) } } else { // Revert with the appropriate error type for the selector used. uint32 selectorUsed; uint32 errorSelector; assembly ("memory-safe") { selectorUsed := and(mload(add(buffer, 0x4)), 0xffffffff) } if (selectorUsed == uint32(IValidationHookModule.preUserOpValidationHook.selector)) { errorSelector = uint32(PreUserOpValidationHookReverted.selector); } else { errorSelector = uint32(UserOpValidationFunctionReverted.selector); } _revertModuleFunction(errorSelector, moduleAddress, entityId); } } function allocateRuntimeValidationCallBuffer(bytes calldata callData, bytes calldata authorization) internal returns (RTCallBuffer result) { // Allocate a call to regular runtime validation. Pre runtime validation hooks lack the `account` field, so // they won't touch the selector portion of this buffer. bytes memory buffer = abi.encodeCall( IValidationModule.validateRuntime, (address(0), uint32(0), msg.sender, msg.value, callData, authorization) ); assembly ("memory-safe") { result := buffer } // Buffer contents, before update: // 0xAAAAAAAA // selector // 0x000: 0x________________________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB // account // 0x020: 0x________________________________________________________CCCCCCCC // entityId // 0x040: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // msg.sender // 0x060: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE // msg.value // 0x080: 0x______________________________________________________________c0 // callData offset // 0x0a0: 0x_____________________________________________________________FFF // authorization offset // 0x0c0... // dynamic fields // Prepare the buffer for pre-runtime validation hooks. _prepareRuntimeCallBufferPreValidationHooks(result); } function invokeRuntimeCallBufferPreValidationHook( RTCallBuffer buffer, HookConfig hookEntity, bytes calldata authorizationSegment ) internal { bool success; address moduleAddress; uint32 entityId; assembly ("memory-safe") { // Load the module address and entity Id entityId := and(shr(64, hookEntity), 0xffffffff) moduleAddress := shr(96, hookEntity) // Update the buffer with the entity Id mstore(add(buffer, 0x44), entityId) // Get the offset of the authorization in the buffer. // The authorization offset is the 6th word in the buffer (0x20 * 5 = 0xa0). // We need to add the buffer length and selector length (0x24) to get the start of the authorization. let authorizationRelativeOffset := mload(add(buffer, 0xc4)) // Convert to an absolute offset // Add the lengths of the selector, buffer length field, and the authorization length field. let authorizationAbsOffset := add(add(buffer, authorizationRelativeOffset), 0x44) // Copy in the authorization segment // Since the buffer's copy of the authorization exceeds the length of any sub-segments, we can safely // write over it. mstore(authorizationAbsOffset, authorizationSegment.length) // If there is a nonzero authorization segment length, copy in the data. if authorizationSegment.length { // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need // to zero out the last word of the buffer to prevent sending garbage data. let roundedDownAuthorizationLength := and(authorizationSegment.length, not(0x1f)) mstore(add(authorizationAbsOffset, add(roundedDownAuthorizationLength, 0x20)), 0) // Copy the authorization segment from calldata into the correct location in the buffer. calldatacopy( add(authorizationAbsOffset, 0x20), authorizationSegment.offset, authorizationSegment.length ) } // The data amount we actually want to call with is: // buffer length - word-align(oldAuthorization length) + word-align(newAuthorization length) - 0x20 (to // skip `account`), // This is equivalent to: // 4 (selector length) + 0x20 (authorization length field) + authorizationRelativeOffset + // word-align(newAuthorization length) let actualCallLength := add(authorizationRelativeOffset, 0x24) // Add in the new authorization length, with word alignment. This is safe to do because the // authorization segment length is guaranteed to be less than the size of the previous entire // authorization length. actualCallLength := add(actualCallLength, and(add(authorizationSegment.length, 0x1f), not(0x1f))) // Perform the call success := call( gas(), moduleAddress, /*value*/ 0, /*argOffset*/ add(buffer, 0x40), // jump over 32 bytes for length, and another 32 bytes for the account /*argSize*/ actualCallLength, /*retOffset*/ codesize(), /*retSize*/ 0 ) } if (!success) { _revertModuleFunction(uint32(PreRuntimeValidationHookReverted.selector), moduleAddress, entityId); } } // Note: we need to add an extra check for codesize > 0 on the module, otherwise EOAs added as runtime // validation would authorize all calls. function invokeRuntimeCallBufferValidation( RTCallBuffer buffer, ModuleEntity moduleEntity, bytes calldata authorizationSegment ) internal { bool success; address moduleAddress; uint32 entityId; assembly ("memory-safe") { // Load the module address and entity Id entityId := and(shr(64, moduleEntity), 0xffffffff) moduleAddress := shr(96, moduleEntity) // Store the account in the `account` field. mstore(add(buffer, 0x24), address()) // Update the buffer with the entity Id mstore(add(buffer, 0x44), entityId) // Fix the calldata offsets of `callData` and `authorization`, due to including the `account` field for // runtime validation. // The offset of calldata should be reset back to 0x0c0. For pre-validation hooks, it was set to 0x0a0. mstore(add(buffer, 0xa4), 0xc0) // Get the offset of the authorization in the buffer. // The authorization offset is the 6th word in the buffer (0x20 * 5 = 0xa0). let authorizationOffsetPtr := add(buffer, 0xc4) // Get the stored value. This will be the edited value for preRuntimeValidationHooks. let authorizationRelativeOffset := mload(authorizationOffsetPtr) // Fix the stored offset value by adding 0x20. authorizationRelativeOffset := add(authorizationRelativeOffset, 0x20) // Correct the authorization relative offset mstore(authorizationOffsetPtr, authorizationRelativeOffset) // Convert to an absolute offset // Add the lengths of the selector and buffer length field. let authorizationAbsOffset := add(add(buffer, authorizationRelativeOffset), 0x24) // Copy in the authorization segment // Since the buffer's copy of the authorization exceeds the length of any sub-segments, we can safely // write over it. mstore(authorizationAbsOffset, authorizationSegment.length) // If there is a nonzero authorization segment length, copy in the data. if authorizationSegment.length { // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need // to zero out the last word of the buffer to prevent sending garbage data. let roundedDownAuthorizationLength := and(authorizationSegment.length, not(0x1f)) mstore(add(authorizationAbsOffset, add(roundedDownAuthorizationLength, 0x20)), 0) // Copy the authorization segment from calldata into the correct location in the buffer. calldatacopy( add(authorizationAbsOffset, 0x20), authorizationSegment.offset, authorizationSegment.length ) } // The data amount we actually want to call with is: // buffer length - word-align(oldAuthorization length) + word-align(newAuthorization length) - 0x20 (to // skip `account`), // This is equivalent to: // 4 (selector length) + 0x20 (authorization length field) + authorizationRelativeOffset + // word-align(newAuthorization length) let actualCallLength := add(authorizationRelativeOffset, 0x24) // Add in the new authorization length, with word alignment. // This is safe to do because the authorization segment length is guaranteed to be less than the size // of the previous entire authorization length. actualCallLength := add(actualCallLength, and(add(authorizationSegment.length, 0x1f), not(0x1f))) // Before performing the call, we need to check that the module has code. // IValidationModule.validateRuntime has no return value, so an EOA added as a validation (perhaps for // direct call validation) would authorize all calls, which is unsafe. Solidity inserts this check by // default, but when we're making calls manually via call buffers, we need to do the check ourselves. if iszero(extcodesize(moduleAddress)) { revert(0, 0) } // Perform the call success := call( gas(), moduleAddress, /*value*/ 0, /*argOffset*/ add(buffer, 0x20), // jump over 32 bytes for length /*argSize*/ actualCallLength, /*retOffset*/ codesize(), /*retSize*/ 0 ) } if (!success) { _revertModuleFunction(uint32(RuntimeValidationFunctionReverted.selector), moduleAddress, entityId); } } function executeRuntimeSelfCall(RTCallBuffer buffer, bytes calldata data) internal { bool bufferExists; assembly ("memory-safe") { bufferExists := iszero(iszero(buffer)) } if (bufferExists) { // We don’t know whether the RTCallBuffer was called only with pre-hooks (skipping RT validation // updates because of SMA), or if it was called with a buffer after a module based RT validation, which // would cause the relative offset of calldata to change. So, when loading the callData for self-exec, // we must not load the relative calldata offset, and must instead use an absolute offset from the // start of the buffer. Using an absolute offset is safe because the abi encoder will only generate // “strict encoding mode” encodings, so it is guaranteed to be in that location. bytes memory callData; assembly ("memory-safe") { // Get the memory address of the length of callData in the buffer. // Because we don't know whether this will be invoked with the RTCallBuffer still as a callData := add(buffer, 0xe4) } // Perform the call, bubbling up revert data on failure. callBubbleOnRevert(address(this), msg.value, callData); } else { // No buffer exists yet, just copy the data to memory transiently and execute it. callBubbleOnRevertTransient(address(this), msg.value, data); } } // Convert a RTCallBuffer to a pre hook call buffer, if the RTCallBuffer exists. If not, allocate a new one. function convertToPreHookCallBuffer(RTCallBuffer buffer, bytes calldata data) internal view returns (PHCallBuffer result) { bool bufferExists; assembly ("memory-safe") { bufferExists := iszero(iszero(buffer)) } if (bufferExists) { // The buffer already has most of what we need, but we need to update the pointer, length, and data // offset. // Buffer transformation: // 0xAAAAAAAA // selector // 0x000: 0x________________________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB account -> discarded // 0x020: 0x________________________________________________________CCCCCCCC entityId -> selector // 0x040: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD msg.sender -> entityId // 0x060: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE msg.value -> sender // 0x080: 0x______________________________________________________________c0 callData offset -> value // 0x0a0: 0x_____________________________________________________________FFF auth offset -> cd offset // 0x0c0: 0x_____________________________________________________________GGG callData length -> stays // This new buffer will be a subset of the existing buffer. PHCallBuffer newBuffer; // Right-align the selector uint32 selector = uint32(IExecutionHookModule.preExecutionHook.selector); assembly ("memory-safe") { // We don’t know whether the RTCallBuffer was called only with pre-hooks (skipping RT validation // updates because of SMA), or if it was called with a buffer after a module based RT validation, // which would cause the relative offset of calldata to change. So, when converting to a pre hook // buffer, we must not load the relative calldata offset, and must instead use an absolute offset // from the start of the buffer. Using an absolute offset is safe because the abi encoder will only // generate “strict encoding mode” encodings, so it is guaranteed to be in that location. let callDataAbsOffset := add(buffer, 0xe4) let callDataSize := mload(callDataAbsOffset) // We must squash existing elements, because the stored offset of authorization causes the other // fields to not be aligned. // We need to copy in the selector, entityId, sender, value, and relative callData offset. // Step back 5 words, to start pasting in the new data. let workingPtr := add(buffer, 0x44) // Paste in the selector mstore(workingPtr, selector) // skip pasting in the entity ID, the caller will squash this later workingPtr := add(workingPtr, 0x40) // Paste in msg.sender mstore(workingPtr, caller()) workingPtr := add(workingPtr, 0x20) // Paste in msg.value mstore(workingPtr, callvalue()) workingPtr := add(workingPtr, 0x20) // Paste in the relative callData offset. This is now 0xa0, to show that it is after the entityId, // sender, value, and offset fields. mstore(workingPtr, 0x80) // Now store the buffer length. This will be directly before the selector, and the returned pointer // will point to this word in memory. newBuffer := add(buffer, 0x40) // word-align the callDataSize callDataSize := and(add(callDataSize, 0x1f), not(0x1f)) mstore(newBuffer, add(callDataSize, 0xa4)) // See `allocateRuntimeCallBuffer` for the buffer layout. } return newBuffer; } else { // We need to allocate and return a new buffer. return allocatePreExecHookCallBuffer(data); } } // Allocate a buffer to call a pre-execution hook. function allocatePreExecHookCallBuffer(bytes calldata data) internal view returns (PHCallBuffer) { bytes memory newBuffer = abi.encodeCall(IExecutionHookModule.preExecutionHook, (uint32(0), msg.sender, msg.value, data)); PHCallBuffer result; assembly ("memory-safe") { result := newBuffer } return result; // Buffer contents: // 0xAAAAAAAA // selector // 0x000: 0x________________________________________________________BBBBBBBB // entityId // 0x020: 0x________________________CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // sender // 0x040: 0xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // value // 0x060: 0x______________________________________________________________80 // callData offset // 0x080... // dynamic fields } function invokePreExecHook(PHCallBuffer buffer, HookConfig hookEntity) internal returns (uint256 returnedBytesSize) { bool success; address moduleAddress; uint32 entityId; assembly ("memory-safe") { // Load the module address and entity Id entityId := and(shr(64, hookEntity), 0xffffffff) moduleAddress := shr(96, hookEntity) // Update the buffer with the entity Id mstore(add(buffer, 0x24), entityId) // Perform the call, storing the first two words of return data into scratch space. success := call( gas(), moduleAddress, /*value*/ 0, /*argOffset*/ add(buffer, 0x20), // jump over 32 bytes for length /*argSize*/ mload(buffer), /*retOffset*/ 0, /*retSize*/ 0x40 ) // Need at least 64 bytes of return data to be considered successful. success := and(success, gt(returndatasize(), 0x3f)) // Only accept return data of "strict encoding" form, where the relative offset is exactly 0x20. success := and(success, eq(mload(0), 0x20)) // Ensure that the reported length of return data does not exceed the actual length. // aka the stored length <= retundatasize() - 0x40 (for the first two values) // No opcode for lte, so the expression equals: // stored length < retundatasize() - 0x3f // Underflow doesn't matter, because success is false anyways if length < 0x40. returnedBytesSize := mload(0x20) success := and(success, lt(returnedBytesSize, sub(returndatasize(), 0x3f))) } if (!success) { _revertModuleFunction(uint32(PreExecHookReverted.selector), moduleAddress, entityId); } } // Converts a PreHookCallBuffer to a `bytes memory`, to use for a self-call in `executeUserOp`. // Handles skipping ahead an extra 4 bytes to omit the `executeUserOp` selector, and updates the stored length // to do so. This will edit the buffer. function getExecuteUOCallData(PHCallBuffer buffer, bytes calldata callData) internal pure returns (bytes memory) { bool bufferExists; assembly ("memory-safe") { bufferExists := iszero(iszero(buffer)) } if (bufferExists) { // At this point, the buffer contains the encoded call to the pre-exec hook, but the data being sent is // `msg.data`, not `userOp.callData`. Re-decoding the user op struct's callData is error-prone, so // instead we just copy-in the provided userOp.callData, squashing the buffer. This is fine because the // buffer will not be reused after this operation. bytes memory result; assembly ("memory-safe") { // Safe to do unchecked because there must have been at least 4 bytes of callData for the // EntryPoint to call `executeUserOp`. let actualCallDataLength := sub(callData.length, 4) // Write over the existing buffer result := buffer // Store the new length mstore(result, actualCallDataLength) if actualCallDataLength { // We don't need to write a zero word because this data will not be word-aligned before sending // Copy in the callData calldatacopy(add(result, 0x20), add(callData.offset, 4), actualCallDataLength) } } return result; } else { // No buffer exists yet, just copy the data to memory and return it. // Skip the first 4 bytes in this function to save the computation on the buffer reuse case. return callData[4:]; } } // DensePostHookData layout // Very tricky to navigate, because we must do so backwards. // type ~= struct[] but in reverse, the caller must advance through it backwards // N instances of: // - post hook address (will be squashed with the selector later, during invocation) // - post hook entity Id // - fixed preExecHookData offset (always 0x40) // - preExecHookData length // - var-length data (right-padded with zeros to be word aligned) // - segment (struct) length (not counting this word, to traverse backwards) // 1 count of post hooks to run. The returned memory pointer will point to this value. function doPreHooks(HookConfig[] memory hooks, PHCallBuffer callBuffer) internal returns (DensePostHookData result) { uint256 hooksLength = hooks.length; // How many "post hooks to run" there are. uint256 resultCount; // Where in memory to start writing the next "post hook to run". bytes32 workingMemPtr; // Start allocating the dense buffer. From this point out, avoid any high-level memory allocations, // otherwise the data-in-flight may be corrupted. assembly ("memory-safe") { workingMemPtr := mload(0x40) } // Run the pre hooks and copy their return data to the dense post hooks data buffer array, if an associated // post exec hook exists. for (uint256 i = hooksLength; i > 0;) { // Decrement here, instead of in the loop update step, to handle the case where the length is 0. unchecked { --i; } HookConfig hookConfig = hooks[i]; if (hookConfig.hasPreHook()) { uint256 returnedBytesSize = invokePreExecHook(callBuffer, hookConfig); // If there is an associated post exec hook, save the return data. if (hookConfig.hasPostHook()) { // Case: both pre and post exec hook, need to save hook info, and pre hook return data workingMemPtr = _appendPostHookToRun(workingMemPtr, hookConfig, returnedBytesSize); ++resultCount; } } else if (hookConfig.hasPostHook()) { // If there is no pre hook, but there is a post hook, we still need to save a placeholder for the // post hook return data. // Case: only post exec hook, need to save hook info, and no pre hook return data // Call the append function with legnth 0 to put no pre hook return data. workingMemPtr = _appendPostHookToRun(workingMemPtr, hookConfig, 0); ++resultCount; } } // Save the length, return a pointer to the length, and update the FMP assembly ("memory-safe") { mstore(workingMemPtr, resultCount) result := workingMemPtr workingMemPtr := add(workingMemPtr, 0x20) mstore(0x40, workingMemPtr) } } function doCachedPostHooks(DensePostHookData postHookData) internal { uint256 postHookCount; uint256 workingMemPtr; assembly ("memory-safe") { postHookCount := mload(postHookData) workingMemPtr := sub(postHookData, 0x20) } uint32 selector = uint32(IExecutionHookModule.postExecutionHook.selector); // Run the post hooks. // This is tricky, unlike normal, we must traverse the data backwards, because the post exec hooks should // be executed in reverse order of the pre exec hooks. for (uint256 i = 0; i < postHookCount; ++i) { bool success; address moduleAddress; uint32 entityId; assembly ("memory-safe") { // The last word of each segment is the segment length let segmentLength := mload(workingMemPtr) // Step the working memory pointer back to the start of the segment, and preserve a copy to // continue the loop workingMemPtr := sub(workingMemPtr, segmentLength) let segmentStart := workingMemPtr // Load the post hook address moduleAddress := mload(workingMemPtr) // Load the entity id, just for the revert message entityId := mload(add(workingMemPtr, 0x20)) // Squash the post hook address field with the selector mstore(workingMemPtr, selector) // Advance the working mem pointer to just before the selector, to prepare to make the call. workingMemPtr := add(workingMemPtr, 0x1c) // Compute the total call length, including the selector // This will be seggment length - 0x1c (28), to take out the space not used in the selector let callLength := sub(segmentLength, 0x1c) // Perform the call success := call( gas(), moduleAddress, /*value*/ 0, /*argOffset*/ workingMemPtr, /*argSize*/ callLength, /*retOffset*/ codesize(), /*retSize*/ 0 ) // Step the working mem pointer back to the previous segment workingMemPtr := sub(segmentStart, 0x20) } if (!success) { _revertModuleFunction(uint32(PostExecHookReverted.selector), moduleAddress, entityId); } } } function allocateSigCallBuffer(bytes32 hash, bytes calldata signature) internal view returns (SigCallBuffer result) { bytes memory buffer = abi.encodeCall( IValidationModule.validateSignature, (address(0), uint32(0), msg.sender, hash, signature) ); assembly ("memory-safe") { result := buffer } // Buffer contents, before update: // 0xAAAAAAAA // selector // 0x000: 0x________________________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB // account // 0x020: 0x________________________________________________________CCCCCCCC // entityId // 0x040: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // msg.sender // 0x060: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE // hash // 0x080: 0x______________________________________________________________a0 // signature offset // 0x0a0... // dynamic fields // Prepare the buffer for pre-signature validation hooks. _prepareSigValidationCallBufferPreSigValidationHooks(result); } function invokePreSignatureValidationHook( SigCallBuffer buffer, HookConfig hookEntity, bytes calldata signatureSegment ) internal view { bool success; address moduleAddress; uint32 entityId; assembly ("memory-safe") { // Load the module address and entity id entityId := and(shr(64, hookEntity), 0xffffffff) moduleAddress := shr(96, hookEntity) // Update the buffer with the entity Id mstore(add(buffer, 0x44), entityId) // Copy in the signature segment // Since the buffer's copy of the signature exceeds the length of any sub-segments, we can safely write // over it. mstore(add(buffer, 0xc4), signatureSegment.length) // If there is a nonzero signature segment length, copy in the data. if signatureSegment.length { // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need // to zero out the last word of the buffer to prevent sending garbage data. let roundedDownSignatureLength := and(signatureSegment.length, not(0x1f)) mstore(add(add(buffer, 0xe4), roundedDownSignatureLength), 0) // Copy in the data calldatacopy(add(buffer, 0xe4), signatureSegment.offset, signatureSegment.length) } // The data amount we actually want to call with is: // 0xa4 (4 byte selector + 5 words of data: entity id, sender, hash, signature offset, signature // length) + word-align(signature length) let actualCallLength := add(0xa4, and(add(signatureSegment.length, 0x1f), not(0x1f))) // Perform the call success := staticcall( gas(), moduleAddress, /*argOffset*/ add(buffer, 0x40), // jump over 32 bytes for length, and another 32 bytes for the account /*argSize*/ actualCallLength, /*retOffset*/ 0, /*retSize*/ 0x20 ) } if (!success) { _revertModuleFunction(uint32(PreSignatureValidationHookReverted.selector), moduleAddress, entityId); } } function invokeSignatureValidation( SigCallBuffer buffer, ModuleEntity validationFunction, bytes calldata signatureSegment ) internal view returns (bytes4 result) { bool success; address moduleAddress; uint32 entityId; assembly ("memory-safe") { // Load the module address and entity id entityId := and(shr(64, validationFunction), 0xffffffff) moduleAddress := shr(96, validationFunction) // Store the account in the `account` field. mstore(add(buffer, 0x24), address()) // Update the buffer with the entity Id mstore(add(buffer, 0x44), entityId) // Fix the calldata offsets of `signature`, due to including the `account` field for signature // validation. mstore(add(buffer, 0xa4), 0xa0) // Copy in the signature segment // Since the buffer's copy of the signature exceeds the length of any sub-segments, we can safely write // over it. mstore(add(buffer, 0xc4), signatureSegment.length) // If there is a nonzero signature segment length, copy in the data. if signatureSegment.length { // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need // to zero out the last word of the buffer to prevent sending garbage data. let roundedDownSignatureLength := and(signatureSegment.length, not(0x1f)) mstore(add(add(buffer, 0xe4), roundedDownSignatureLength), 0) // Copy in the data calldatacopy(add(buffer, 0xe4), signatureSegment.offset, signatureSegment.length) } // The data amount we actually want to call with is: // 0xc4 (4 byte selector + 6 words of data: account, entity id, sender, hash, signature offset, // signature length) + word-align(signature length) let actualCallLength := add(0xc4, and(add(signatureSegment.length, 0x1f), not(0x1f))) // Perform the call success := and( // Yul evaluates expressions from right to left, so `returndatasize` will evaluate after // `staticcall`. gt(returndatasize(), 0x1f), staticcall( gas(), moduleAddress, /*argOffset*/ add(buffer, 0x20), // jump over 32 bytes for length, and another 32 bytes for the account /*argSize*/ actualCallLength, /*retOffset*/ 0, /*retSize*/ 0x20 ) ) } if (success) { assembly ("memory-safe") { // Otherwise, we return the first word of the return data as the signature validation result result := mload(0) // If any of the lower 28 bytes are nonzero, it would be an abi decoding failure. if shl(32, result) { revert(0, 0) } } } else { _revertModuleFunction(uint32(SignatureValidationFunctionReverted.selector), moduleAddress, entityId); } } /// @notice Appends a post hook to run to the dense post hook data buffer. /// @param workingMemPtr The current working memory pointer /// @param hookConfig The hook configuration /// @param returnedBytesSize The size of the returned bytes from the pre hook /// @return The new working memory pointer function _appendPostHookToRun(bytes32 workingMemPtr, HookConfig hookConfig, uint256 returnedBytesSize) private pure returns (bytes32) { // Each segment starts out at a length of 4 words: // - post hook address // - post hook entity Id // - fixed preExecHookData offset (always 0x40) // - preHookReturnData length // Add to this the word-aligned length of the pre hook return data. uint256 segmentLength = 0x80; assembly ("memory-safe") { // Load the module address and entity Id let entityId := and(shr(64, hookConfig), 0xffffffff) let moduleAddress := shr(96, hookConfig) // Get the word-aligned data to copy length let alignedDataLength := and(add(returnedBytesSize, 0x1f), not(0x1f)) segmentLength := add(segmentLength, alignedDataLength) // Start writing to memory: // Store the post hook address mstore(workingMemPtr, moduleAddress) workingMemPtr := add(workingMemPtr, 0x20) // Store the post hook entity Id mstore(workingMemPtr, entityId) workingMemPtr := add(workingMemPtr, 0x20) // Store the fixed preExecHookData offset mstore(workingMemPtr, 0x40) workingMemPtr := add(workingMemPtr, 0x20) // Store the preHookReturnData length mstore(workingMemPtr, returnedBytesSize) workingMemPtr := add(workingMemPtr, 0x20) // Copy in the pre hook return data, if any exists if returnedBytesSize { // Zero out the last memory word to encode in strict ABI mode let roundedDownDataLength := and(returnedBytesSize, not(0x1f)) mstore(add(workingMemPtr, roundedDownDataLength), 0) // Copy in the data returndatacopy(workingMemPtr, 0x40, returnedBytesSize) workingMemPtr := add(workingMemPtr, alignedDataLength) } // Store the overall segment length at the end mstore(workingMemPtr, segmentLength) workingMemPtr := add(workingMemPtr, 0x20) } return workingMemPtr; } function _revertModuleFunction(uint32 errorSelector, address moduleAddress, uint32 entityId) private pure { // All of the module function reverts have the same parameter layout: // - module address // - entity Id // - revert data assembly ("memory-safe") { let m := mload(0x40) // Write in order of entityId -> address -> selector, to avoid masking or shifts. mstore(add(m, 0x18), entityId) mstore(add(m, 0x14), moduleAddress) mstore(m, errorSelector) mstore(add(m, 0x40), 0x40) // fixed offset for the revert data mstore(add(m, 0x60), returndatasize()) if returndatasize() { // Store a zero in the last word of the revert data, to do strict ABI-encoding for the error. let roundedDownDataLength := and(returndatasize(), not(0x1f)) mstore(add(m, add(0x80, roundedDownDataLength)), 0) returndatacopy(add(m, 0x80), 0, returndatasize()) } let roundedUpDataLength := and(add(returndatasize(), 0x1f), not(0x1f)) // 4 bytes for the selector, and 0x60 for the 3 words of fixed-size data. let totalRevertDataLength := add(0x64, roundedUpDataLength) revert(add(m, 0x1c), totalRevertDataLength) } } function _prepareRuntimeCallBufferPreValidationHooks(RTCallBuffer buffer) private pure { uint32 selector = uint32(IValidationHookModule.preRuntimeValidationHook.selector); assembly ("memory-safe") { // Update the buffer with the selector. This will squash a portion of the `account` param for runtime // validation, but that will be restored before calling. mstore(add(buffer, 0x24), selector) // Fix the calldata offsets of `callData` and `authorization`, due to excluding the `account` field. // The offset of calldata starts out as 0x0c0, but for pre-validation hooks, it should be 0x0a0. mstore(add(buffer, 0xa4), 0xa0) // The offset of authorization should be decremented by one word. let authorizationOffsetPtr := add(buffer, 0xc4) // Get the stored value. This will be wrong for preRuntimeValidationHooks, because the buffer size is // smaller by 1 word. let authorizationOffset := mload(authorizationOffsetPtr) // Fix the stored offset value mstore(authorizationOffsetPtr, sub(authorizationOffset, 0x20)) } } function _prepareSigValidationCallBufferPreSigValidationHooks(SigCallBuffer buffer) private pure { uint32 selector = uint32(IValidationHookModule.preSignatureValidationHook.selector); assembly ("memory-safe") { // Update the buffer with the selector. This will squash a portion of the `account` param for signature // validation, but that will be restored before calling. mstore(add(buffer, 0x24), selector) // Fix the calldata offset of `signature`, due to excluding the `account` field. // The offset of the signature starts out as 0xa0, but for pre-validation hooks, it should be 0x80. mstore(add(buffer, 0xa4), 0x80) } } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {HookConfig} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {ExecutionStorage, ValidationStorage} from "../account/AccountStorage.sol"; import {LinkedListSet, LinkedListSetLib, SENTINEL_VALUE, SetValue} from "./LinkedListSetLib.sol"; type MemSnapshot is uint256; /// @title Memory Management Library /// @author Alchemy /// @notice A library for managing memory in ModularAccount. Handles loading data from storage into memory, and /// manipulating the free memory pointer. library MemManagementLib { /// @notice Load execution hooks associated both with a validation function and an execution selector. /// @param execData The execution storage struct to load from. /// @param valData The validation storage struct to load from. /// @return hooks An array of `HookConfig` items, representing the execution hooks. function loadExecHooks(ExecutionStorage storage execData, ValidationStorage storage valData) internal view returns (HookConfig[] memory hooks) { // Load selector-assoc hooks first, then validation-assoc, because execution order is reversed // This next code segment is adapted from the function LinkedListSetLib.getAll. mapping(bytes32 => bytes32) storage llsMap = execData.executionHooks.map; uint256 size = 0; bytes32 cursor = llsMap[SENTINEL_VALUE]; // Dynamically allocate the returned array as we iterate through the set, since we don't know the size // beforehand. // This is accomplished by first writing to memory after the free memory pointer, // then updating the free memory pointer to cover the newly-allocated data. // To the compiler, writes to memory after the free memory pointer are considered "memory safe". // See https://docs.soliditylang.org/en/v0.8.22/assembly.html#memory-safety // Stack variable lifting done when compiling with via-ir will only ever place variables into memory // locations below the current free memory pointer, so it is safe to compile this library with via-ir. // See https://docs.soliditylang.org/en/v0.8.22/yul.html#memoryguard assembly ("memory-safe") { // It is critical that no other memory allocations occur between: // - loading the value of the free memory pointer into `ret` // - updating the free memory pointer to point to the newly-allocated data, which is done after all // the values have been written. hooks := mload(0x40) } while (!LinkedListSetLib.isSentinel(cursor) && cursor != bytes32(0)) { unchecked { ++size; } // Place the item into the return array manually. Since the size was just incremented, it will point to // the next location to write to. assembly ("memory-safe") { mstore(add(hooks, mul(size, 0x20)), cursor) } cursor = llsMap[cursor]; } // Load validation-assoc hooks uint256 validationAssocHooksLength = valData.executionHookCount; llsMap = valData.executionHooks.map; // Notably, we invert the mapping lookup ordering for validation-assoc hooks, because we know the length // ahead-of-time, thus saving an `sload`. This is why the cursor starts at SENTINEL_VALUE. cursor = SENTINEL_VALUE; for (uint256 i = 0; i < validationAssocHooksLength; ++i) { unchecked { ++size; } cursor = llsMap[cursor]; assembly ("memory-safe") { mstore(add(hooks, mul(size, 0x20)), cursor) } } assembly ("memory-safe") { // Update the free memory pointer with the now-known length of the array. mstore(0x40, add(hooks, mul(add(size, 1), 0x20))) // Set the length of the array. mstore(hooks, size) } return hooks; } /// @notice Load execution hooks associated with an execution selector. /// @param execData The execution storage struct to load from. /// @return hooks An array of `HookConfig` items, representing the execution hooks. function loadExecHooks(ExecutionStorage storage execData) internal view returns (HookConfig[] memory) { HookConfig[] memory hooks; SetValue[] memory hooksSet = LinkedListSetLib.getAll(execData.executionHooks); // SetValue is internally a bytes31, and HookConfig is a bytes25, which are both left-aligned. This cast is // safe so long as only HookConfig entries are added to the set. assembly ("memory-safe") { hooks := hooksSet } return hooks; } /// @notice Load execution hooks associated with a validation function. /// @param valData The validation storage struct to load from. /// @return hooks An array of `HookConfig` items, representing the execution hooks. function loadExecHooks(ValidationStorage storage valData) internal view returns (HookConfig[] memory) { uint256 validationAssocHooksLength = valData.executionHookCount; return _loadValidationAssociatedHooks(validationAssocHooksLength, valData.executionHooks); } /// @notice Load validation hooks associated with a validation function. /// @param valData The validation storage struct to load from. /// @return hooks An array of `HookConfig` items, representing the validation hooks. function loadValidationHooks(ValidationStorage storage valData) internal view returns (HookConfig[] memory) { uint256 validationHookCount = valData.validationHookCount; return _loadValidationAssociatedHooks(validationHookCount, valData.validationHooks); } /// @notice Load all selectors that have been added to a validation function. /// @param valData The validation storage struct to load from. /// @return selectors An array of the selectors the validation function is allowed to validate. function loadSelectors(ValidationStorage storage valData) internal view returns (bytes4[] memory selectors) { SetValue[] memory selectorsSet = LinkedListSetLib.getAll(valData.selectors); // SetValue is internally a bytes31, and both bytes4 and bytes31 are left-aligned. This cast is safe so // long as only bytes4 entries are added to the set. assembly ("memory-safe") { selectors := selectorsSet } return selectors; } /// @notice Reverses an array of `HookConfig` items in place. function reverseArr(HookConfig[] memory hooks) internal pure { bytes32[] memory casted; // Cast to bytes32[] to use the shared reverseArr function assembly ("memory-safe") { casted := hooks } _reverseArr(casted); } /// @notice Reverses an array of `bytes4` items in place. function reverseArr(bytes4[] memory selectors) internal pure { bytes32[] memory casted; // Cast to bytes32[] to use the shared reverseArr function assembly ("memory-safe") { casted := selectors } _reverseArr(casted); } /// @notice If the callData is an encoded function call to IModularAccount.execute, retrieves the target of the /// call. /// @param callData The calldata to check. /// @return target The target of the call. function getExecuteTarget(bytes calldata callData) internal pure returns (address) { address target; assembly ("memory-safe") { target := and(calldataload(add(callData.offset, 4)), 0xffffffffffffffffffffffffffffffffffffffff) } return target; } /// @notice Captures a snapshot of the free memory pointer. /// @return The snapshot of the free memory pointer. function freezeFMP() internal pure returns (MemSnapshot) { MemSnapshot snapshot; assembly ("memory-safe") { snapshot := mload(0x40) } return snapshot; } /// @notice Restores the free memory pointer to a previous snapshot. /// @dev This invalidates any memory allocated since the snapshot was taken. /// @param snapshot The snapshot to restore to. function restoreFMP(MemSnapshot snapshot) internal pure { assembly ("memory-safe") { mstore(0x40, snapshot) } } /// @notice Used to load both pre validation hooks and pre execution hooks, associated with a validation /// function. The caller must first get the length of the hooks from the ValidationStorage struct. function _loadValidationAssociatedHooks(uint256 hookCount, LinkedListSet storage hooks) private view returns (HookConfig[] memory) { HookConfig[] memory hookArr = new HookConfig[](hookCount); mapping(bytes32 => bytes32) storage llsMap = hooks.map; bytes32 cursor = SENTINEL_VALUE; for (uint256 i = 0; i < hookCount; ++i) { cursor = llsMap[cursor]; hookArr[i] = HookConfig.wrap(bytes25(cursor)); } return hookArr; } function _reverseArr(bytes32[] memory hooks) private pure { uint256 len = hooks.length; uint256 halfLen = len / 2; for (uint256 i = 0; i < halfLen; ++i) { uint256 j = len - i - 1; (hooks[i], hooks[j]) = (hooks[j], hooks[i]); } } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {DIRECT_CALL_VALIDATION_ENTITY_ID} from "@erc6900/reference-implementation/helpers/Constants.sol"; import {ModuleEntity, ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol"; import { ValidationConfig, ValidationConfigLib } from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol"; import {ValidationStorage} from "../account/AccountStorage.sol"; // A type representing a validation lookup key and flags for validation options. // The validation lookup key is a tagged union between a direct call validation address and a validation entity ID. type ValidationLocator is uint168; // Layout: // Unused // 0x0000000000000000000000__________________________________________ // Either the direct call validation's address, or the entity ID for non-direct-call validation. // 0x______________________AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__ // Validation options // 0x______________________________________________________________BB // ValidationOptions layout: // 0b00000___ // Unused // 0b_____A__ // is direct call validation (union tag) // 0b______B_ // has deferred action // 0b_______C // is global validation // A type representing only the validation lookup key, with validation options masked out except for the // direct call validation flag. type ValidationLookupKey is uint168; using ValidationLocatorLib for ValidationLocator global; using ValidationLocatorLib for ValidationLookupKey global; library ValidationLocatorLib { using ValidationConfigLib for ValidationConfig; uint8 internal constant _VALIDATION_TYPE_GLOBAL = 1; uint8 internal constant _HAS_DEFERRED_ACTION = 2; uint8 internal constant _IS_DIRECT_CALL_VALIDATION = 4; function moduleEntity(ValidationLookupKey _lookupKey, ValidationStorage storage validationStorage) internal view returns (ModuleEntity result) { if (_lookupKey.isDirectCallValidation()) { result = ModuleEntityLib.pack(_lookupKey.directCallAddress(), DIRECT_CALL_VALIDATION_ENTITY_ID); } else { result = ModuleEntityLib.pack(validationStorage.module, _lookupKey.entityId()); } } // User op nonce, 4337 mandated layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________ // Parallel Nonce Key // 0x________________________________________________BBBBBBBBBBBBBBBB // Sequential Nonce Key // User op nonce, Alchemy MA usage: // With non-direct call validation // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__________________________ // Parallel Nonce Key // 0x______________________________________BBBBBBBB__________________ // Validation Entity ID // 0x______________________________________________CC________________ // Options byte // 0x________________________________________________BBBBBBBBBBBBBBBB // Sequential Nonce Key // With direct call validation // 0xAAAAAA__________________________________________________________ // Parallel Nonce Key // 0x______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB__________________ // Caller address of direct-call // validation // 0x______________________________________________CC________________ // Options byte // 0x________________________________________________BBBBBBBBBBBBBBBB // Sequential Nonce Key function loadFromNonce(uint256 nonce) internal pure returns (ValidationLocator result) { assembly ("memory-safe") { nonce := shr(64, nonce) let validationType := and(nonce, _IS_DIRECT_CALL_VALIDATION) switch validationType case 0 { // If not using direct call validation, the validation locator contains a 4-byte entity ID // Mask it to the lower 5 bytes result := and(nonce, 0xFFFFFFFFFF) } default { // If using direct call validation, the validation locator contains a 20-byte address // Mask it to the lower 21 bytes result := and(nonce, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) } } } // executeRuntimeValidation authorization layout, and isValidSignature signature layout // [1-byte options][4-byte validation id OR 20-byte address of direct call validation][remainder] // With non-direct call validation // 0xAA______________ // Validation Type // 0x__BBBBBBBB______ // Validation Entity ID // 0x__________CCC... // Remainder // With direct call validation // 0xAA______________________________________________ // Validation Type // 0x__BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB______ // Caller address of direct-call validation // 0x__________________________________________CCC... // Remainder function loadFromSignature(bytes calldata signature) internal pure returns (ValidationLocator result, bytes calldata remainder) { assembly ("memory-safe") { // Regular validation requires at least 5 bytes. Direct call validation requires at least 21 bytes, // checked later. if lt(signature.length, 5) { revert(0, 0) } result := calldataload(signature.offset) let validationOptions := shr(248, result) switch and(validationOptions, _IS_DIRECT_CALL_VALIDATION) case 0 { // If not using direct call validation, the validation locator contains a 32-byte entity ID // Result contains: // 0xAA______________________________________________________________ // Validation Type // 0x__BBBBBBBB______________________________________________________ // Validation Entity ID // 0x__________CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Remainder bits and/or // zeros // We need to clear the upper byte by shifting left 1 bytes (8 bits), then shift right 28 bytes // (224 bits), leaving only the entity ID. result := shr(224, shl(8, result)) // Next, we need to set the validation type, which is 0 in this branch result := or(shl(8, result), validationOptions) // Advance the remainder by 5 bytes remainder.offset := add(signature.offset, 5) remainder.length := sub(signature.length, 5) } default { // Direct call validation requires at least 21 bytes if lt(signature.length, 21) { revert(0, 0) } // If using direct call validation, the validation locator contains a 20-byte address // Result contains: // 0xAA______________________________________________________________ // Validation Type // 0x__BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB______________________ // Caller address of // direct-call validation // 0x__________________________________________CCCCCCCCCCCCCCCCCCCCCC // Remainder bits and/or // zeros // So we need to clear the upper byte by shifting left 1 bytes (8 bits), then shift right 12 // bytes (96 bits) to get the address. result := shr(96, shl(8, result)) // Next, we need to set the validation type result := or(shl(8, result), validationOptions) // Advance the remainder by 21 bytes remainder.offset := add(signature.offset, 21) remainder.length := sub(signature.length, 21) } } } // Only safe to call if the lookup has been asserted to be a direct call validation. function directCallAddress(ValidationLookupKey _lookupKey) internal pure returns (address result) { assembly ("memory-safe") { result := and(shr(8, _lookupKey), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) } } // Only safe to call if the lookup has been asserted to be a non-direct call validation. function entityId(ValidationLookupKey _lookupKey) internal pure returns (uint32 result) { assembly ("memory-safe") { result := and(shr(8, _lookupKey), 0xFFFFFFFF) } } function isGlobal(ValidationLocator locator) internal pure returns (bool) { return (ValidationLocator.unwrap(locator) & _VALIDATION_TYPE_GLOBAL) != 0; } function hasDeferredAction(ValidationLocator locator) internal pure returns (bool) { return (ValidationLocator.unwrap(locator) & _HAS_DEFERRED_ACTION) != 0; } function isDirectCallValidation(ValidationLookupKey _lookupKey) internal pure returns (bool) { return (ValidationLookupKey.unwrap(_lookupKey) & _IS_DIRECT_CALL_VALIDATION) != 0; } function configToLookupKey(ValidationConfig validationConfig) internal pure returns (ValidationLookupKey result) { if (validationConfig.entityId() == DIRECT_CALL_VALIDATION_ENTITY_ID) { result = ValidationLookupKey.wrap( uint168(uint160(validationConfig.module())) << 8 | _IS_DIRECT_CALL_VALIDATION ); } else { result = ValidationLookupKey.wrap(uint168(uint160(validationConfig.entityId())) << 8); } } function moduleEntityToLookupKey(ModuleEntity _moduleEntity) internal pure returns (ValidationLookupKey result) { (address module, uint32 _entityId) = ModuleEntityLib.unpack(_moduleEntity); if (_entityId == DIRECT_CALL_VALIDATION_ENTITY_ID) { result = ValidationLookupKey.wrap(uint168(uint160(module)) << 8 | _IS_DIRECT_CALL_VALIDATION); } else { result = ValidationLookupKey.wrap(uint168(uint160(_entityId)) << 8); } } function directCallLookupKey(address directCallValidation) internal pure returns (ValidationLookupKey result) { result = ValidationLookupKey.wrap(uint168(uint160(directCallValidation)) << 8 | _IS_DIRECT_CALL_VALIDATION); } function lookupKey(ValidationLocator locator) internal pure returns (ValidationLookupKey result) { assembly ("memory-safe") { result := and(locator, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04) } } // Packing functions. These should not be used in the account, but in scripts and tests. function pack(uint32 _entityId, bool _isGlobal, bool _hasDeferredAction) internal pure returns (ValidationLocator) { uint168 result = uint168(_entityId) << 8; if (_isGlobal) { result |= _VALIDATION_TYPE_GLOBAL; } if (_hasDeferredAction) { result |= _HAS_DEFERRED_ACTION; } return ValidationLocator.wrap(result); } function packDirectCall(address directCallValidation, bool _isGlobal, bool _hasDeferredAction) internal pure returns (ValidationLocator) { uint168 result = uint168(uint160(directCallValidation)) << 8 | _IS_DIRECT_CALL_VALIDATION; if (_isGlobal) { result |= _VALIDATION_TYPE_GLOBAL; } if (_hasDeferredAction) { result |= _HAS_DEFERRED_ACTION; } return ValidationLocator.wrap(result); } function packNonce(uint32 validationEntityId, bool _isGlobal, bool _hasDeferredAction) internal pure returns (uint256 result) { result = uint256(validationEntityId) << 8; if (_isGlobal) { result |= _VALIDATION_TYPE_GLOBAL; } if (_hasDeferredAction) { result |= _HAS_DEFERRED_ACTION; } // Finally, shift left to make space for the sequential nonce key result <<= 64; } function packNonceDirectCall(address directCallValidation, bool _isGlobal, bool _hasDeferredAction) internal pure returns (uint256 result) { result = uint256(uint160(directCallValidation)) << 8 | _IS_DIRECT_CALL_VALIDATION; if (_isGlobal) { result |= _VALIDATION_TYPE_GLOBAL; } if (_hasDeferredAction) { result |= _HAS_DEFERRED_ACTION; } // Finally, shift left to make space for the sequential nonce key result <<= 64; } function packSignature(uint32 validationEntityId, bool _isGlobal, bytes memory signature) internal pure returns (bytes memory result) { uint8 options = 0; if (_isGlobal) { options |= _VALIDATION_TYPE_GLOBAL; } return bytes.concat(abi.encodePacked(options, uint32(validationEntityId)), signature); } function packSignatureDirectCall( address directCallValidation, bool _isGlobal, bool _hasDeferredAction, bytes memory signature ) internal pure returns (bytes memory result) { uint8 options = _IS_DIRECT_CALL_VALIDATION; if (_isGlobal) { options |= _VALIDATION_TYPE_GLOBAL; } if (_hasDeferredAction) { options |= _HAS_DEFERRED_ACTION; } return bytes.concat(abi.encodePacked(options, uint160(directCallValidation)), signature); } // Converts a module entity to a locator. function packFromModuleEntity(ModuleEntity _moduleEntity, bool _isGlobal, bool _hasDeferredAction) internal pure returns (ValidationLocator) { uint168 result; (address module, uint32 _entityId) = ModuleEntityLib.unpack(_moduleEntity); if (_entityId == DIRECT_CALL_VALIDATION_ENTITY_ID) { result = uint168(uint160(module)) << 8 | _IS_DIRECT_CALL_VALIDATION; } else { result = uint168(_entityId) << 8; } if (_isGlobal) { result |= _VALIDATION_TYPE_GLOBAL; } if (_hasDeferredAction) { result |= _HAS_DEFERRED_ACTION; } return ValidationLocator.wrap(result); } // Operators function eq(ValidationLookupKey a, ValidationLookupKey b) internal pure returns (bool) { return ValidationLookupKey.unwrap(a) == ValidationLookupKey.unwrap(b); } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {IAccount} from "@eth-infinitism/account-abstraction/interfaces/IAccount.sol"; import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol"; import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol"; /// @title Account Base /// @author Alchemy /// @dev An optimized implementation of a base account contract for ERC-4337. /// Provides a public view function for getting the EntryPoint address, but does not provide one for getting the /// nonce. The nonce may be retrieved from the EntryPoint contract. /// Implementing contracts should override the _validateUserOp function to provide account-specific validation /// logic. abstract contract AccountBase is IAccount { IEntryPoint internal immutable _ENTRY_POINT; error NotEntryPoint(); constructor(IEntryPoint _entryPoint) { _ENTRY_POINT = _entryPoint; } /// @inheritdoc IAccount function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) external override returns (uint256 validationData) { _requireFromEntryPoint(); validationData = _validateUserOp(userOp, userOpHash); // Pay the prefund if necessary. assembly ("memory-safe") { if missingAccountFunds { // Ignore failure (it's EntryPoint's job to verify, not the account's). pop(call(gas(), caller(), missingAccountFunds, codesize(), 0x00, codesize(), 0x00)) } } } /// @notice Gets the entry point for this account /// @return entryPoint The entry point for this account function entryPoint() external view returns (IEntryPoint) { return _ENTRY_POINT; } /// @notice Account-specific implementation of user op validation. Override this function to define the /// account's validation logic. function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) internal virtual returns (uint256 validationData); /// @notice Revert if the sender is not the EntryPoint. function _requireFromEntryPoint() internal view { if (msg.sender != address(_ENTRY_POINT)) { revert NotEntryPoint(); } } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {AccountStorage, getAccountStorage} from "./AccountStorage.sol"; /// @title Account Storage Initializable /// @author Alchemy /// @notice A contract mixin that provides the functionality of OpenZeppelin's Initializable contract, using the /// custom storage layout defined by the AccountStorage struct. /// @dev The implementation logic here is modified from OpenZeppelin's Initializable contract from v5.0. abstract contract AccountStorageInitializable { /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev The contract is already initialized. */ error InvalidInitialization(); /// @notice Modifier to put on function intended to be called only once per implementation /// @dev Reverts if the contract has already been initialized modifier initializer() { AccountStorage storage $ = getAccountStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$.initializing; uint64 initialized = $.initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $.initialized = 1; if (isTopLevelCall) { $.initializing = true; } _; if (isTopLevelCall) { $.initializing = false; emit Initialized(1); } } /// @notice Internal function to disable calls to initialization functions /// @dev Reverts if the contract is currently initializing. function _disableInitializers() internal virtual { AccountStorage storage $ = getAccountStorage(); if ($.initializing) { revert InvalidInitialization(); } if ($.initialized != type(uint8).max) { $.initialized = type(uint8).max; emit Initialized(type(uint8).max); } } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import { HookConfig, IModularAccount, ModuleEntity } from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import { ExecutionDataView, IModularAccountView, ValidationDataView } from "@erc6900/reference-implementation/interfaces/IModularAccountView.sol"; import {IAccountExecute} from "@eth-infinitism/account-abstraction/interfaces/IAccountExecute.sol"; import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol"; import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IModularAccountBase} from "../interfaces/IModularAccountBase.sol"; import {MemManagementLib} from "../libraries/MemManagementLib.sol"; import {ValidationLocatorLib} from "../libraries/ValidationLocatorLib.sol"; import {AccountBase} from "./AccountBase.sol"; import {ExecutionStorage, ValidationStorage, getAccountStorage} from "./AccountStorage.sol"; /// @title Modular Account View /// @author Alchemy /// @notice This abstract contract implements the two view functions to get validation and execution data for an /// account. abstract contract ModularAccountView is IModularAccountView { /// @inheritdoc IModularAccountView function getExecutionData(bytes4 selector) external view override returns (ExecutionDataView memory data) { ExecutionStorage storage executionStorage = getAccountStorage().executionStorage[selector]; if (_isNativeFunction(uint32(selector))) { bool isGlobalValidationAllowed = _isGlobalValidationAllowedNativeFunction(uint32(selector)); data.module = address(this); data.skipRuntimeValidation = !isGlobalValidationAllowed; data.allowGlobalValidation = isGlobalValidationAllowed; if (!_isWrappedNativeFunction(uint32(selector))) { // The native function does not run execution hooks associated with its selector, so // we can return early. return data; } } else { data.module = executionStorage.module; data.skipRuntimeValidation = executionStorage.skipRuntimeValidation; data.allowGlobalValidation = executionStorage.allowGlobalValidation; } HookConfig[] memory hooks = MemManagementLib.loadExecHooks(executionStorage); MemManagementLib.reverseArr(hooks); data.executionHooks = hooks; } /// @inheritdoc IModularAccountView function getValidationData(ModuleEntity validationFunction) external view override returns (ValidationDataView memory data) { ValidationStorage storage validationStorage = getAccountStorage().validationStorage[ValidationLocatorLib.moduleEntityToLookupKey(validationFunction)]; data.validationFlags = validationStorage.validationFlags; data.validationHooks = MemManagementLib.loadValidationHooks(validationStorage); MemManagementLib.reverseArr(data.validationHooks); HookConfig[] memory hooks = MemManagementLib.loadExecHooks(validationStorage); MemManagementLib.reverseArr(hooks); data.executionHooks = hooks; bytes4[] memory selectors = MemManagementLib.loadSelectors(validationStorage); MemManagementLib.reverseArr(selectors); data.selectors = selectors; } function _isNativeFunction(uint32 selector) internal pure virtual returns (bool) { return ( _isGlobalValidationAllowedNativeFunction(selector) || selector == uint32(AccountBase.entryPoint.selector) || selector == uint32(AccountBase.validateUserOp.selector) || selector == uint32(IERC1155Receiver.onERC1155BatchReceived.selector) || selector == uint32(IERC1155Receiver.onERC1155Received.selector) || selector == uint32(IERC1271.isValidSignature.selector) || selector == uint32(IERC165.supportsInterface.selector) || selector == uint32(IERC721Receiver.onERC721Received.selector) || selector == uint32(IModularAccount.accountId.selector) || selector == uint32(IModularAccountView.getExecutionData.selector) || selector == uint32(IModularAccountView.getValidationData.selector) || selector == uint32(UUPSUpgradeable.proxiableUUID.selector) ); } /// @dev Check whether a function is a native function that allows global validation. function _isGlobalValidationAllowedNativeFunction(uint32 selector) internal pure virtual returns (bool) { return ( _isWrappedNativeFunction(selector) || selector == uint32(IAccountExecute.executeUserOp.selector) || selector == uint32(IModularAccount.executeWithRuntimeValidation.selector) ); } /// @dev Check whether a function is a native function that has the `wrapNativeFunction` modifier applied, /// which means it runs execution hooks associated with its selector. function _isWrappedNativeFunction(uint32 selector) internal pure virtual returns (bool) { return ( selector == uint32(IModularAccount.execute.selector) || selector == uint32(IModularAccount.executeBatch.selector) || selector == uint32(IModularAccount.installExecution.selector) || selector == uint32(IModularAccount.installValidation.selector) || selector == uint32(IModularAccount.uninstallExecution.selector) || selector == uint32(IModularAccount.uninstallValidation.selector) || selector == uint32(IModularAccountBase.performCreate.selector) || selector == uint32(UUPSUpgradeable.upgradeToAndCall.selector) ); } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {MAX_VALIDATION_ASSOC_HOOKS} from "@erc6900/reference-implementation/helpers/Constants.sol"; import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol"; import { HookConfig, IModularAccount, ModuleEntity, ValidationConfig, ValidationFlags } from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol"; import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol"; import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol"; import {ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol"; import {ValidationConfigLib} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol"; import {LinkedListSet, LinkedListSetLib} from "../libraries/LinkedListSetLib.sol"; import {MemManagementLib} from "../libraries/MemManagementLib.sol"; import {ModuleInstallCommonsLib} from "../libraries/ModuleInstallCommonsLib.sol"; import {ValidationLocatorLib} from "../libraries/ValidationLocatorLib.sol"; import {ValidationStorage, getAccountStorage, toSetValue} from "./AccountStorage.sol"; /// @title Module Manager Internals /// @author Alchemy /// @notice This abstract contract hosts the internal installation and uninstallation methods of execution and /// validation functions. Methods here update the account storage. abstract contract ModuleManagerInternals is IModularAccount { using LinkedListSetLib for LinkedListSet; using ModuleEntityLib for ModuleEntity; using ValidationConfigLib for ValidationConfig; using HookConfigLib for HookConfig; error ArrayLengthMismatch(); error PreValidationHookDuplicate(); error ValidationEntityIdInUse(); error ValidationAlreadySet(bytes4 selector, ModuleEntity validationFunction); error ValidationAssocHookLimitExceeded(); function _setValidationFunction( ValidationStorage storage validationStorage, ValidationConfig validationConfig, bytes4[] calldata selectors ) internal { // To allow for flag updates and appending hooks and selectors, two cases should be considered: // - stored module address is zero - store the new validation module address // - stored module address already holds the address of the validation module being installed - update // flags and selectors. // If the stored module address does not match, revert, as the validation entity ID must be unique over the // account. address storedAddress = validationStorage.module; (address moduleAddress,, ValidationFlags validationFlags) = validationConfig.unpackUnderlying(); if (storedAddress == address(0)) { validationStorage.module = moduleAddress; } else if (storedAddress != moduleAddress) { revert ValidationEntityIdInUse(); } validationStorage.validationFlags = validationFlags; uint256 length = selectors.length; for (uint256 i = 0; i < length; ++i) { bytes4 selector = selectors[i]; if (!validationStorage.selectors.tryAdd(toSetValue(selector))) { revert ValidationAlreadySet(selector, validationConfig.moduleEntity()); } } } function _removeValidationFunction(ValidationStorage storage validationStorage) internal { validationStorage.module = address(0); validationStorage.validationFlags = ValidationFlags.wrap(0); validationStorage.validationHookCount = 0; validationStorage.executionHookCount = 0; } function _installValidation( ValidationConfig validationConfig, bytes4[] calldata selectors, bytes calldata installData, bytes[] calldata hooks ) internal { ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[ValidationLocatorLib.configToLookupKey(validationConfig)]; _setValidationFunction(_validationStorage, validationConfig, selectors); uint256 length = hooks.length; for (uint256 i = 0; i < length; ++i) { HookConfig hookConfig = HookConfig.wrap(bytes25(hooks[i][:25])); bytes calldata hookData = hooks[i][25:]; if (hookConfig.isValidationHook()) { // Increment the stored length of validation hooks, and revert if the limit is exceeded. // Safety: // validationHookCount is uint8, so math operations here should never overflow unchecked { if (uint256(_validationStorage.validationHookCount) + 1 > MAX_VALIDATION_ASSOC_HOOKS) { revert ValidationAssocHookLimitExceeded(); } ++_validationStorage.validationHookCount; } if (!_validationStorage.validationHooks.tryAdd(toSetValue(hookConfig))) { revert PreValidationHookDuplicate(); } ModuleInstallCommonsLib.onInstall( hookConfig.module(), hookData, type(IValidationHookModule).interfaceId ); } else { // Hook is an execution hook // Safety: // validationHookCount is uint8, so math operations here should never overflow unchecked { if (uint256(_validationStorage.executionHookCount) + 1 > MAX_VALIDATION_ASSOC_HOOKS) { revert ValidationAssocHookLimitExceeded(); } ++_validationStorage.executionHookCount; } ModuleInstallCommonsLib.addExecHooks(_validationStorage.executionHooks, hookConfig); ModuleInstallCommonsLib.onInstall( hookConfig.module(), hookData, type(IExecutionHookModule).interfaceId ); } } ModuleInstallCommonsLib.onInstall( validationConfig.module(), installData, type(IValidationModule).interfaceId ); emit ValidationInstalled(validationConfig.module(), validationConfig.entityId()); } function _uninstallValidation( ModuleEntity validationFunction, bytes calldata uninstallData, bytes[] calldata hookUninstallDatas ) internal { ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[ValidationLocatorLib.moduleEntityToLookupKey(validationFunction)]; bool onUninstallSuccess = true; // Send `onUninstall` to hooks if (hookUninstallDatas.length > 0) { HookConfig[] memory execHooks = MemManagementLib.loadExecHooks(_validationStorage); HookConfig[] memory validationHooks = MemManagementLib.loadValidationHooks(_validationStorage); // If any uninstall data is provided, assert it is of the correct length. if (hookUninstallDatas.length != validationHooks.length + execHooks.length) { revert ArrayLengthMismatch(); } // Hook uninstall data is provided in the order of pre validation hooks, then execution hooks. uint256 hookIndex = 0; uint256 length = validationHooks.length; for (uint256 i = 0; i < length; ++i) { bytes calldata hookData = hookUninstallDatas[hookIndex]; (address hookModule,) = ModuleEntityLib.unpack(validationHooks[i].moduleEntity()); onUninstallSuccess = onUninstallSuccess && ModuleInstallCommonsLib.onUninstall(hookModule, hookData); hookIndex++; } length = execHooks.length; for (uint256 i = 0; i < length; ++i) { bytes calldata hookData = hookUninstallDatas[hookIndex]; address hookModule = execHooks[i].module(); onUninstallSuccess = onUninstallSuccess && ModuleInstallCommonsLib.onUninstall(hookModule, hookData); hookIndex++; } } // Clear all stored hooks. The lengths of the hooks are cleared in `_removeValidationFunction`. _validationStorage.validationHooks.clear(); _validationStorage.executionHooks.clear(); // Clear selectors _validationStorage.selectors.clear(); // Clear validation function data. // Must be done at the end, because the hook lengths are accessed in the loop above. _removeValidationFunction(_validationStorage); (address module, uint32 entityId) = ModuleEntityLib.unpack(validationFunction); onUninstallSuccess = onUninstallSuccess && ModuleInstallCommonsLib.onUninstall(module, uninstallData); emit ValidationUninstalled(module, entityId, onUninstallSuccess); } }
// This file is part of Modular Account. // // Copyright 2024 Alchemy Insights, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General // Public License as published by the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with this program. If not, see // <https://www.gnu.org/licenses/>. pragma solidity ^0.8.26; import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; /// @title Token Receiver /// @author Alchemy /// @notice Token receiver, supports tokens callbacks to allow the account to receive supported tokens. abstract contract TokenReceiver is IERC721Receiver, IERC1155Receiver { /// @inheritdoc IERC721Receiver function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) { return IERC721Receiver.onERC721Received.selector; } /// @inheritdoc IERC1155Receiver function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure override returns (bytes4) { return IERC1155Receiver.onERC1155Received.selector; } /// @inheritdoc IERC1155Receiver function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) external pure override returns (bytes4) { return IERC1155Receiver.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; import {IModule} from "./IModule.sol"; interface IExecutionHookModule is IModule { /// @notice Run the pre execution hook specified by the `entityId`. /// @dev To indicate the entire call should revert, the function MUST revert. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param sender The caller address. /// @param value The call value. /// @param data The calldata sent. For `executeUserOp` calls, hook modules should receive the full msg.data. /// @return Context to pass to a post execution hook, if present. An empty bytes array MAY be returned. function preExecutionHook(uint32 entityId, address sender, uint256 value, bytes calldata data) external returns (bytes memory); /// @notice Run the post execution hook specified by the `entityId`. /// @dev To indicate the entire call should revert, the function MUST revert. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param preExecHookData The context returned by its associated pre execution hook. function postExecutionHook(uint32 entityId, bytes calldata preExecHookData) external; }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol"; import {IModule} from "./IModule.sol"; interface IValidationHookModule is IModule { /// @notice Run the pre user operation validation hook specified by the `entityId`. /// @dev Pre user operation validation hooks MUST NOT return an authorizer value other than 0 or 1. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param userOp The user operation. /// @param userOpHash The user operation hash. /// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes). function preUserOpValidationHook(uint32 entityId, PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256); /// @notice Run the pre runtime validation hook specified by the `entityId`. /// @dev To indicate the entire call should revert, the function MUST revert. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param sender The caller address. /// @param value The call value. /// @param data The calldata sent. /// @param authorization Additional data for the hook to use. function preRuntimeValidationHook( uint32 entityId, address sender, uint256 value, bytes calldata data, bytes calldata authorization ) external; /// @notice Run the pre signature validation hook specified by the `entityId`. /// @dev To indicate the call should revert, the function MUST revert. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param sender The caller address. /// @param hash The hash of the message being signed. /// @param signature The signature of the message. function preSignatureValidationHook(uint32 entityId, address sender, bytes32 hash, bytes calldata signature) external view; }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol"; import {IModule} from "./IModule.sol"; interface IValidationModule is IModule { /// @notice Run the user operation validation function specified by the `entityId`. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param userOp The user operation. /// @param userOpHash The user operation hash. /// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes). function validateUserOp(uint32 entityId, PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256); /// @notice Run the runtime validation function specified by the `entityId`. /// @dev To indicate the entire call should revert, the function MUST revert. /// @param account the account to validate for. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param sender The caller address. /// @param value The call value. /// @param data The calldata sent. /// @param authorization Additional data for the validation function to use. function validateRuntime( address account, uint32 entityId, address sender, uint256 value, bytes calldata data, bytes calldata authorization ) external; /// @notice Validates a signature using ERC-1271. /// @dev To indicate the entire call should revert, the function MUST revert. /// @param account the account to validate for. /// @param entityId An identifier that routes the call to different internal implementations, should there /// be more than one. /// @param sender the address that sent the ERC-1271 request to the smart account /// @param hash the hash of the ERC-1271 request /// @param signature the signature of the ERC-1271 request /// @return The ERC-1271 `MAGIC_VALUE` if the signature is valid, or 0xFFFFFFFF if invalid. function validateSignature( address account, uint32 entityId, address sender, bytes32 hash, bytes calldata signature ) external view returns (bytes4); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; import "./PackedUserOperation.sol"; /** * The interface exposed by a paymaster contract, who agrees to pay the gas for user's operations. * A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction. */ interface IPaymaster { enum PostOpMode { // User op succeeded. opSucceeded, // User op reverted. Still has to pay for gas. opReverted, // Only used internally in the EntryPoint (cleanup after postOp reverts). Never calling paymaster with this value postOpReverted } /** * Payment validation: check if paymaster agrees to pay. * Must verify sender is the entryPoint. * Revert to reject this request. * Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted). * The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns. * @param userOp - The user operation. * @param userOpHash - Hash of the user's request data. * @param maxCost - The maximum cost of this transaction (based on maximum gas and gas price from userOp). * @return context - Value to send to a postOp. Zero length to signify postOp is not required. * @return validationData - Signature and time-range of this operation, encoded the same as the return * value of validateUserOperation. * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, * other values are invalid for paymaster. * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" * <6-byte> validAfter - first timestamp this operation is valid * Note that the validation code cannot use block.timestamp (or block.number) directly. */ function validatePaymasterUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost ) external returns (bytes memory context, uint256 validationData); /** * Post-operation handler. * Must verify sender is the entryPoint. * @param mode - Enum with the following options: * opSucceeded - User operation succeeded. * opReverted - User op reverted. The paymaster still has to pay for gas. * postOpReverted - never passed in a call to postOp(). * @param context - The context value returned by validatePaymasterUserOp * @param actualGasCost - Actual gas used so far (without this postOp call). * @param actualUserOpFeePerGas - the gas price this UserOp pays. This value is based on the UserOp's maxFeePerGas * and maxPriorityFee (and basefee) * It is not the same as tx.gasprice, which is what the bundler pays. */ function postOp( PostOpMode mode, bytes calldata context, uint256 actualGasCost, uint256 actualUserOpFeePerGas ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface. */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. */ function getSupportedInterfaces( address account, bytes4[] memory interfaceIds ) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * * Some precompiled contracts will falsely indicate support for a given interface, so caution * should be exercised when using this function. * * Interface identification is specified in ERC-165. */ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { // prepare call bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId)); // perform static call bool success; uint256 returnSize; uint256 returnValue; assembly { success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) returnSize := returndatasize() returnValue := mload(0x00) } return success && returnSize >= 0x20 && returnValue > 0; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.20; // Index marking the start of the data for the validation function. uint8 constant RESERVED_VALIDATION_DATA_INDEX = type(uint8).max; // Maximum number of validation-associated hooks that can be registered. uint8 constant MAX_VALIDATION_ASSOC_HOOKS = type(uint8).max; // Magic value for the Entity ID of direct call validation. uint32 constant DIRECT_CALL_VALIDATION_ENTITY_ID = type(uint32).max;
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; import {HookConfig, ModuleEntity, ValidationFlags} from "../interfaces/IModularAccount.sol"; /// @dev Represents data associated with a specific function selector. struct ExecutionDataView { // The module that implements this execution function. // If this is a native function, the address must be the address of the account. address module; // Whether or not the function needs runtime validation, or can be called by anyone. The function can still be // state changing if this flag is set to true. // Note that even if this is set to true, user op validation will still be required, otherwise anyone could // drain the account of native tokens by wasting gas. bool skipRuntimeValidation; // Whether or not a global validation function may be used to validate this function. bool allowGlobalValidation; // The execution hooks for this function selector. HookConfig[] executionHooks; } struct ValidationDataView { // ValidationFlags layout: // 0b00000___ // unused // 0b_____A__ // isGlobal // 0b______B_ // isSignatureValidation // 0b_______C // isUserOpValidation ValidationFlags validationFlags; // The validation hooks for this validation function. HookConfig[] validationHooks; // Execution hooks to run with this validation function. HookConfig[] executionHooks; // The set of selectors that may be validated by this validation function. bytes4[] selectors; } interface IModularAccountView { /// @notice Get the execution data for a selector. /// @dev If the selector is a native function, the module address will be the address of the account. /// @param selector The selector to get the data for. /// @return The execution data for this selector. function getExecutionData(bytes4 selector) external view returns (ExecutionDataView memory); /// @notice Get the validation data for a validation function. /// @dev If the selector is a native function, the module address will be the address of the account. /// @param validationFunction The validation function to get the data for. /// @return The validation data for this validation function. function getValidationData(ModuleEntity validationFunction) external view returns (ValidationDataView memory); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; import "./PackedUserOperation.sol"; interface IAccount { /** * Validate user's signature and nonce * the entryPoint will make the call to the recipient only if this validation call returns successfully. * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). * This allows making a "simulation call" without a valid signature * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure. * * @dev Must validate caller is the entryPoint. * Must validate the signature and nonce * @param userOp - The operation that is about to be executed. * @param userOpHash - Hash of the user's request data. can be used as the basis for signature. * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint. * This is the minimum amount to transfer to the sender(entryPoint) to be * able to make the call. The excess is left as a deposit in the entrypoint * for future calls. Can be withdrawn anytime using "entryPoint.withdrawTo()". * In case there is a paymaster in the request (or the current deposit is high * enough), this value will be zero. * @return validationData - Packaged ValidationData structure. use `_packValidationData` and * `_unpackValidationData` to encode and decode. * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, * otherwise, an address of an "authorizer" contract. * <6-byte> validUntil - Last timestamp this operation is valid. 0 for "indefinite" * <6-byte> validAfter - First timestamp this operation is valid * If an account doesn't use time-range, it is enough to * return SIG_VALIDATION_FAILED value (1) for signature failure. * Note that the validation code cannot use block.timestamp (or block.number) directly. */ function validateUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds ) external returns (uint256 validationData); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC1967-compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.20; import {IBeacon} from "../beacon/IBeacon.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. */ library ERC1967Utils { // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. // This will be fixed in Solidity 0.8.21. At that point we should remove these events. /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "@eth-infinitism/account-abstraction/=node_modules/account-abstraction/contracts/", "account-abstraction/=node_modules/account-abstraction/contracts/", "@openzeppelin/=lib/openzeppelin-contracts/", "@alchemy/light-account/=lib/light-account/", "solady/=node_modules/solady/src/", "@erc6900/reference-implementation/=node_modules/@erc6900/reference-implementation/src/", "forge-gas-snapshot/=lib/forge-gas-snapshot/src/", "forge-std/=lib/forge-std/src/", "webauthn-sol/=lib/webauthn-sol/", "FreshCryptoLib/=lib/webauthn-sol/lib/FreshCryptoLib/solidity/src/", "openzeppelin-contracts/=lib/webauthn-sol/lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 50000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"contract IEntryPoint","name":"entryPoint","type":"address"},{"internalType":"contract ExecutionInstallDelegate","name":"executionInstallDelegate","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"CreateFailed","type":"error"},{"inputs":[],"name":"DeferredActionSignatureInvalid","type":"error"},{"inputs":[],"name":"DeferredValidationHasValidationHooks","type":"error"},{"inputs":[{"internalType":"HookConfig","name":"hookConfig","type":"bytes25"}],"name":"ExecutionHookAlreadySet","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"InterfaceNotSupported","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"ModuleInstallCallbackFailed","type":"error"},{"inputs":[],"name":"NonCanonicalEncoding","type":"error"},{"inputs":[],"name":"NotEntryPoint","type":"error"},{"inputs":[],"name":"PreValidationHookDuplicate","type":"error"},{"inputs":[],"name":"RequireUserOperationContext","type":"error"},{"inputs":[],"name":"SegmentOutOfOrder","type":"error"},{"inputs":[],"name":"SelfCallRecursionDepthExceeded","type":"error"},{"inputs":[{"internalType":"ModuleEntity","name":"validationFunction","type":"bytes24"}],"name":"SignatureValidationInvalid","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"ModuleEntity","name":"validationFunction","type":"bytes24"},{"internalType":"address","name":"aggregator","type":"address"}],"name":"UnexpectedAggregator","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"UnrecognizedFunction","type":"error"},{"inputs":[],"name":"UpgradeFailed","type":"error"},{"inputs":[{"internalType":"ModuleEntity","name":"validationFunction","type":"bytes24"}],"name":"UserOpValidationInvalid","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"ModuleEntity","name":"validationFunction","type":"bytes24"}],"name":"ValidationAlreadySet","type":"error"},{"inputs":[],"name":"ValidationAssocHookLimitExceeded","type":"error"},{"inputs":[],"name":"ValidationEntityIdInUse","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"ValidationFunctionMissing","type":"error"},{"inputs":[],"name":"ValidationSignatureSegmentMissing","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"module","type":"address"},{"components":[{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"bool","name":"skipRuntimeValidation","type":"bool"},{"internalType":"bool","name":"allowGlobalValidation","type":"bool"}],"internalType":"struct ManifestExecutionFunction[]","name":"executionFunctions","type":"tuple[]"},{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"bool","name":"isPreHook","type":"bool"},{"internalType":"bool","name":"isPostHook","type":"bool"}],"internalType":"struct ManifestExecutionHook[]","name":"executionHooks","type":"tuple[]"},{"internalType":"bytes4[]","name":"interfaceIds","type":"bytes4[]"}],"indexed":false,"internalType":"struct ExecutionManifest","name":"manifest","type":"tuple"}],"name":"ExecutionInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"module","type":"address"},{"indexed":false,"internalType":"bool","name":"onUninstallSucceeded","type":"bool"},{"components":[{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"bool","name":"skipRuntimeValidation","type":"bool"},{"internalType":"bool","name":"allowGlobalValidation","type":"bool"}],"internalType":"struct ManifestExecutionFunction[]","name":"executionFunctions","type":"tuple[]"},{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"bool","name":"isPreHook","type":"bool"},{"internalType":"bool","name":"isPostHook","type":"bool"}],"internalType":"struct ManifestExecutionHook[]","name":"executionHooks","type":"tuple[]"},{"internalType":"bytes4[]","name":"interfaceIds","type":"bytes4[]"}],"indexed":false,"internalType":"struct ExecutionManifest","name":"manifest","type":"tuple"}],"name":"ExecutionUninstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"module","type":"address"},{"indexed":true,"internalType":"uint32","name":"entityId","type":"uint32"}],"name":"ValidationInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"module","type":"address"},{"indexed":true,"internalType":"uint32","name":"entityId","type":"uint32"},{"indexed":false,"internalType":"bool","name":"onUninstallSucceeded","type":"bool"}],"name":"ValidationUninstalled","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"accountId","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"name":"executeBatch","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"executeUserOp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"authorization","type":"bytes"}],"name":"executeWithRuntimeValidation","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"getExecutionData","outputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bool","name":"skipRuntimeValidation","type":"bool"},{"internalType":"bool","name":"allowGlobalValidation","type":"bool"},{"internalType":"HookConfig[]","name":"executionHooks","type":"bytes25[]"}],"internalType":"struct ExecutionDataView","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ModuleEntity","name":"validationFunction","type":"bytes24"}],"name":"getValidationData","outputs":[{"components":[{"internalType":"ValidationFlags","name":"validationFlags","type":"uint8"},{"internalType":"HookConfig[]","name":"validationHooks","type":"bytes25[]"},{"internalType":"HookConfig[]","name":"executionHooks","type":"bytes25[]"},{"internalType":"bytes4[]","name":"selectors","type":"bytes4[]"}],"internalType":"struct ValidationDataView","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ValidationConfig","name":"validationConfig","type":"bytes25"},{"internalType":"bytes4[]","name":"selectors","type":"bytes4[]"},{"internalType":"bytes","name":"installData","type":"bytes"},{"internalType":"bytes[]","name":"hooks","type":"bytes[]"}],"name":"initializeWithValidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"module","type":"address"},{"components":[{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"bool","name":"skipRuntimeValidation","type":"bool"},{"internalType":"bool","name":"allowGlobalValidation","type":"bool"}],"internalType":"struct ManifestExecutionFunction[]","name":"executionFunctions","type":"tuple[]"},{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"bool","name":"isPreHook","type":"bool"},{"internalType":"bool","name":"isPostHook","type":"bool"}],"internalType":"struct ManifestExecutionHook[]","name":"executionHooks","type":"tuple[]"},{"internalType":"bytes4[]","name":"interfaceIds","type":"bytes4[]"}],"internalType":"struct ExecutionManifest","name":"manifest","type":"tuple"},{"internalType":"bytes","name":"moduleInstallData","type":"bytes"}],"name":"installExecution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"ValidationConfig","name":"validationConfig","type":"bytes25"},{"internalType":"bytes4[]","name":"selectors","type":"bytes4[]"},{"internalType":"bytes","name":"installData","type":"bytes"},{"internalType":"bytes[]","name":"hooks","type":"bytes[]"}],"name":"installValidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bool","name":"isCreate2","type":"bool"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"performCreate","outputs":[{"internalType":"address","name":"createdAddr","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"module","type":"address"},{"components":[{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"bool","name":"skipRuntimeValidation","type":"bool"},{"internalType":"bool","name":"allowGlobalValidation","type":"bool"}],"internalType":"struct ManifestExecutionFunction[]","name":"executionFunctions","type":"tuple[]"},{"components":[{"internalType":"bytes4","name":"executionSelector","type":"bytes4"},{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"bool","name":"isPreHook","type":"bool"},{"internalType":"bool","name":"isPostHook","type":"bool"}],"internalType":"struct ManifestExecutionHook[]","name":"executionHooks","type":"tuple[]"},{"internalType":"bytes4[]","name":"interfaceIds","type":"bytes4[]"}],"internalType":"struct ExecutionManifest","name":"manifest","type":"tuple"},{"internalType":"bytes","name":"moduleUninstallData","type":"bytes"}],"name":"uninstallExecution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"ModuleEntity","name":"validationFunction","type":"bytes24"},{"internalType":"bytes","name":"uninstallData","type":"bytes"},{"internalType":"bytes[]","name":"hookUninstallData","type":"bytes[]"}],"name":"uninstallValidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"missingAccountFunds","type":"uint256"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e03461017357601f615c7838819003918201601f19168301916001600160401b03831184841017610178578084926040948552833981010312610173578051906001600160a01b038216820361017357602001516001600160a01b0381169190829003610173576080523060a0527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd005460ff8160401c166101625760fe196001600160401b038216016100ff575b5060c052604051615ae9908161018f8239608051818181610e3301528181611502015281816115c3015281816126360152612b3d015260a051818181610fbb0152611114015260c051816120ba0152f35b6001600160401b03191660ff9081177f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd00556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1386100ae565b63f92ee8a960e01b60005260046000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040526004361015610026575b36156100245761001c61252b565b602081519101f35b005b60003560e01c80621a63e91461014957806301ffc9a714610180578063150b7a021461017b5780631626ba7e1461017657806319822f7c146101715780631bbf564c1461016c57806334fcd5be146101675780634f1ef2861461016257806352d1902d1461015d5780635998db5c14610158578063757c8a26146101535780638dd7712f1461014e57806393b1dc61146101495780639cfd7cff14610144578063b0d691fe1461013f578063b61d27f61461013a578063b6b1ccfe14610135578063bc197c8114610130578063d31b575b1461012b578063e919a62314610126578063f23a6e61146101215763f2680c0f0361000e57611e64565b611dd3565b611b7b565b611ab7565b61193a565b61164b565b61153a565b6114b7565b61143a565b61027f565b611318565b611280565b611162565b6110e2565b610f5f565b610ddc565b610973565b610579565b6103a3565b610312565b6102c3565b73ffffffffffffffffffffffffffffffffffffffff8116036101a357565b600080fd5b35906101b382610185565b565b9181601f840112156101a35782359167ffffffffffffffff83116101a357602083818601950101116101a357565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101a35760043561021981610185565b9160243567ffffffffffffffff81116101a35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82850301126101a357600401916044359067ffffffffffffffff82116101a35761027b916004016101b5565b9091565b346101a357610024610290366101e3565b9291909161209f565b7fffffffff000000000000000000000000000000000000000000000000000000008116036101a357565b346101a35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357602061030860043561030381610299565b6120f5565b6040519015158152f35b346101a35760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35761034c600435610185565b610357602435610185565b60643567ffffffffffffffff81116101a3576103779036906004016101b5565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b346101a35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760243560043567ffffffffffffffff82116101a35761041461040e74ffffffffffffffffffffffffffffffffffffffff049336906004016101b5565b90612a20565b92919390931692610478838261047261046d8874ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b6135a3565b94613db1565b9082515b808015610519577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0191845191820391600183019081116105145782116105145761050f956104cf9260ff165b91613e20565b939296919093966105096104e385896123a6565b517fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690565b86613f13565b61047c565b612abd565b610566610533888661052b8a88613fa4565b929091614014565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681529081906020820190565b0390f35b90816101209103126101a35790565b346101a35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a3576105cb61064a91369060040161056a565b602435604435916105da612b26565b60009060208101356105eb816131d8565b6105f9610100840184612281565b81929192819461060b84600216151590565b6107aa575b50505061065760608501916106258387612281565b74ffffffffffffffffffffffffffffffffffffffff04839293169b8c92600116151590565b156107a2576000926137b6565b60ff6106b06106a68a74ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b5460b01c60ff1690565b1615159081610739575b5061070f576105669686956106ce9461442e565b90801561070857906106df916145ba565b915b6106f7575b506040519081529081906020820190565b60009081803892335af150386106e6565b50916106e1565b7f5f49f00a0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f8dd7712f00000000000000000000000000000000000000000000000000000000915061079961079361078d7fffffffff000000000000000000000000000000000000000000000000000000009388612281565b90612b8f565b90612c93565b161415386106ba565b6001926137b6565b65ffffffffffff97508293955061087c94506108769061084c6108706107ea6107e16107db61079389899a99612b8f565b60e01c90565b63ffffffff1690565b9a8b9361086961086388876108578c6108346107e16107db61079361081861081188612cf9565b8987612b9d565b98909761082d61082782612cf9565b91612d07565b9187612c7b565b9a8d6108518d61084c61084685612d07565b94612d07565b612d15565b92612c7b565b929091604051966142a0565b91604052565b1660a01b90565b99612d07565b91612c7b565b91388080610610565b9181601f840112156101a35782359167ffffffffffffffff83116101a3576020808501948460051b0101116101a357565b9060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126101a3576004357fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000811681036101a3579160243567ffffffffffffffff81116101a3578161092d91600401610885565b9290929160443567ffffffffffffffff81116101a35781610950916004016101b5565b929092916064359067ffffffffffffffff82116101a35761027b91600401610885565b346101a357610981366108b6565b90919293946109ec61099161261c565b966109e461099e8a614604565b74ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b928984614689565b60005b828110610ab257610024878773ffffffffffffffffffffffffffffffffffffffff63ffffffff610a858d610a798c610a72610a6c7fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000085165b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690565b60601c90565b9687614b0f565b60401c63ffffffff1690565b1691167fc36a28045e90a1163d24d4216c8cfd8c44c4e835a486fb84d511d6b9e0736db9600080a361295f565b610af7610ad2610acc610ac6848789612d22565b90612bd8565b90612d39565b7fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690565b90610b0d610b06828688612d22565b8091612be6565b9092670100000000000000811615610c8057845460a81c60ff169060ff60018184160111610c5657610b8b91610ad29060010160ff165b87547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1660a89190911b75ff00000000000000000000000000000000000000000016178755565b90610beb610be7610bde7fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000085165b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690565b60018801614b4a565b1590565b610c2c57600193610c21610a6c610c26947fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690565b614ad4565b016109ef565b7f298ac3da0000000000000000000000000000000000000000000000000000000060005260046000fd5b7fe330dd260000000000000000000000000000000000000000000000000000000060005260046000fd5b90610c90855460ff9060b01c1690565b9360ff60018187160111610c5657610d13610a6c610a47610d1895610d06610cbe60019a600160ff91011690565b8b547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1660b09190911b76ff0000000000000000000000000000000000000000000016178b55565b610ad28160028c016148db565b61497c565b610c26565b919082519283825260005b848110610d49575050601f19601f8460006020809697860101520116010190565b80602080928401015182828601015201610d28565b602081016020825282518091526040820191602060408360051b8301019401926000915b838310610d9157505050505090565b9091929394602080610dcd837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528951610d1d565b97019301930191939290610d82565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a357610e26903690600401610885565b610e2e61261c565b6060337f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1614610f0b5750610e778261235d565b9160005b818110610e9e5750506105669250610e929061295f565b60405191829182610d5e565b80610ee7610eb7610eb2600194868a612232565b612277565b6020610ec484878b612232565b013590610edf610ed585888c612232565b6040810190612281565b929091612f6b565b610eef612f80565b610ef982876123a6565b52610f0481866123a6565b5001610e7b565b91909260005b828110610f2757505050610e926105669261295f565b80610f59610f3b610eb26001948787612232565b6020610f48848888612232565b013590610edf610ed5858989612232565b01610f11565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357600435610f9581610185565b60243567ffffffffffffffff81116101a357610fb59036906004016101b5565b919091307f0000000000000000000000000000000000000000000000000000000000000000146110c957610fe761261c565b9073ffffffffffffffffffffffffffffffffffffffff60009316906352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc602060016004601d865afa51036110bb57817fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8580a280827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55611097575b836110948461295f565b80f35b908184926040519687378538925af4156110b257828061108a565b503d90823e3d90fd5b6355299b496001526004601dfd5b639f03a0266000526004601cfd5b60009103126101a357565b346101a35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357307f0000000000000000000000000000000000000000000000000000000000000000036110c95760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043560243567ffffffffffffffff81116101a3576111af9036906004016101b5565b906044359283151584036101a3576064356111c861261c565b94846040519485376001146112215750f05b8015611213576111ec6105669261295f565b60405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b637e16b8cd6000526004601cfd5b929190f56111da565b906020808351928381520192019060005b8181106112485750505090565b82517fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001684526020938401939092019160010161123b565b346101a35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760606112c56004356112c081610299565b6123ba565b6105666040519283926020845273ffffffffffffffffffffffffffffffffffffffff81511660208501526020810151151560408501526040810151151582850152015160808084015260a083019061122a565b346101a35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a35761136a61002491369060040161056a565b611372612b26565b61141b6114156113ed6113e874ffffffffffffffffffffffffffffffffffffffff046113a160208701356131d8565b1674ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b613208565b6000908051611420575b6114048261140f9261332a565b946060810190612281565b91613440565b306134e8565b61295f565b905061140f6114046114313661323e565b929150506113f7565b346101a35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357610566604080519061147b8183612322565b601d82527f616c6368656d792e6d6f64756c61722d6163636f756e742e322e302e30000000602083015251918291602083526020830190610d1d565b346101a35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b906020611537928181520190610d1d565b90565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043561157081610185565b6044359060243567ffffffffffffffff83116101a3576115ac61159a6105669436906004016101b5565b906115a361261c565b93606095612f6b565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303611607575b6115f39061295f565b604051918291602083526020830190610d1d565b90506115f3611614612f80565b9190506115ea565b600435907fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000821682036101a357565b346101a35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35761168261161c565b60243567ffffffffffffffff81116101a3576116a29036906004016101b5565b9060443567ffffffffffffffff81116101a3576116c3903690600401610885565b90926116cd61261c565b936116da61099e87613514565b90600193806117e9575b50506100249561173d826116fd60016117529501614f39565b61170960028201614f39565b61171560038201614f39565b80547fffffffffffffffffff0000000000000000000000000000000000000000000000169055565b606081901c9160409190911c63ffffffff1690565b919093836117ae575b5050604051911515825263ffffffff169173ffffffffffffffffffffffffffffffffffffffff16907f43f7309d11ba6b2e180e9ab8a6da09d2fa1f585d7daed4b26c1c7f2a90b867a290602090a361295f565b7f43f7309d11ba6b2e180e9ab8a6da09d2fa1f585d7daed4b26c1c7f2a90b867a292935063ffffffff916117e29186614e85565b929161175b565b6117f283613208565b6117fb846135a3565b916118098351835190612d15565b810361191057919290600093805185915b81831061188f575050508051926000925b84841061183b57505050506116e4565b9091929394976118726001916118528b8686612d22565b90611863610a6c6104e38b8b6123a6565b8361187d575b505050996132fd565b95940192919061182b565b6118879350614e85565b388080611869565b909194929395986118f06001916118a78c878b612d22565b906118e061173d6118bb6104e38d8a6123a6565b7fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690565b50836118fe575b5050509a6132fd565b95019190959392949561181a565b6119089350614e85565b3880806118e7565b7fa24a13a60000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357611974600435610185565b61197f602435610185565b60443567ffffffffffffffff81116101a35761199f903690600401610885565b505060643567ffffffffffffffff81116101a3576119c1903690600401610885565b505060843567ffffffffffffffff81116101a3576119e39036906004016101b5565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b906020825260ff81511660208301526060611a52611a3d60208401516080604087015260a086019061122a565b6040840151601f19868303018487015261122a565b910151916080601f19828403019101526020808351928381520192019060005b818110611a7f5750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611a72565b346101a35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357610566611af161161c565b60405190611afe82612301565b60008252611b64600360208401606081526040850160608152611b4a611b2e61099e606089019760608952613514565b9260ff845460a01c168852611b42846135a3565b809152614c82565b611b5382613208565b90611b5d82614c82565b5201614c20565b90611b6e82614c82565b5260405191829182611a10565b346101a357611b89366108b6565b7f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0054969590949193919067ffffffffffffffff611bd660ff60408b901c16159967ffffffffffffffff1690565b1680159081611dcb575b6001149081611dc1575b159081611db8575b50611d8e57611c739688611c6a60017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000007f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd005416177f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0055565b611d1357612d9f565b611c7957005b611ce47fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0054167f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0055565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b611d89680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd005416177f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0055565b612d9f565b7ff92ee8a90000000000000000000000000000000000000000000000000000000060005260046000fd5b90501538611bf2565b303b159150611bea565b899150611be0565b346101a35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357611e0d600435610185565b611e18602435610185565b60843567ffffffffffffffff81116101a357611e389036906004016101b5565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a357611eae9036906004016101b5565b60243567ffffffffffffffff81116101a35761040e611ed19136906004016101b5565b74ffffffffffffffffffffffffffffffffffffffff04839592931694611f43611f3a8774ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b91600116151590565b156120945790611f5760005b8787866137b6565b8094611fb38592611fab61046d8a74ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b968387613af3565b9385515b808015612029577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01938751918203916001830190811161051457821161051457612022986120089260ff166104c9565b9692999190969961201c6104e3888c6123a6565b89613b9a565b9392611fb7565b505061205e61205086956113e8610566988c6120488d6120649a613fa4565b929091615219565b60009080516120815761332a565b93613a0e565b61207561206f612f80565b9161295f565b60405191829182611526565b905061208e8484886139c5565b9061332a565b90611f576001611f4f565b505050506120ab61261c565b600060405136828237389036907f00000000000000000000000000000000000000000000000000000000000000005af4156120e9576101b39061295f565b6040513d6000823e3d90fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167fffffffff0000000000000000000000000000000000000000000000000000000081146121fd577f150b7a0200000000000000000000000000000000000000000000000000000000811480156121d4575b80156121ab575b6121a5576000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd03602052604060002054151590565b50600190565b507f01ffc9a700000000000000000000000000000000000000000000000000000000811461216f565b507f4e2312e0000000000000000000000000000000000000000000000000000000008114612168565b50600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91908110156122725760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1813603018212156101a3570190565b612203565b3561153781610185565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101a3570180359067ffffffffffffffff82116101a3576020019181360383136101a357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6080810190811067ffffffffffffffff82111761231d57604052565b6122d2565b90601f601f19910116810190811067ffffffffffffffff82111761231d57604052565b67ffffffffffffffff811161231d5760051b60200190565b9061236782612345565b6123746040519182612322565b828152601f196123848294612345565b019060005b82811061239557505050565b806060602080938501015201612389565b80518210156122725760209160051b010190565b90604051916123c883612301565b60008352600060208401526000604084015260608084015282612436827fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b9160e01c61244381612f9e565b1561249a57610be78161246e61245b612473946130ec565b3086528015602087015215156040860152565b61312c565b61249557506001612485915b01614c20565b61248e81614c82565b6060830152565b925050565b508161250a600192604061250361248596546124e66124cc8273ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168552565b6124fa60a082901c60ff1615156020860152565b60a81c60ff1690565b1515910152565b61247f565b67ffffffffffffffff811161231d57601f01601f191660200190565b7fffffffff000000000000000000000000000000000000000000000000000000006000351673ffffffffffffffffffffffffffffffffffffffff6125ba827fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b54169081156125ef57506125e46125cf61261c565b916040519036825236600060208401376134e8565b61153761206f612f80565b7ffcfc5aad0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633141580612955575b806128c6575b1561283b573360081b74ffffffffffffffffffffffffffffffffffffffff00166004179161269383366135b8565b6126e061046d8474ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b92835180612829575b805b6127e757506115379293506127c3906127bd6127767fffffffff00000000000000000000000000000000000000000000000000000000600035167fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b9174ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b90613c02565b60009181516127d3575b5061332a565b6127e0919250369061397c565b90386127cd565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0193846128223661281c6104e384866123a6565b86613b57565b90946126eb565b91506128353636613a32565b916126e9565b90611537906128c16128bc7fffffffff00000000000000000000000000000000000000000000000000000000600035167fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b6131cc565b6127c3565b50612950610be76129467fffffffff00000000000000000000000000000000000000000000000000000000600035167fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b5460a01c60ff1690565b612665565b503033141561265f565b601f19815191019060005b81811061297657505050565b8251809303928351601f196000602087015193635d413a8188527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4389101601c890183865af1950194156129ce57505060010161296a565b604051916018830152601482015263f19fc59381526040808201523d60608201523d612a06575b601c601f19601f3d01166064019101fd5b60006080601f193d16830101523d6000608083013e6129f5565b91600582106101a35782358060f81c9060048216600014612a8857601584106101a35760501c74ffffffffffffffffffffffffffffffffffffffff00161792601501917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb0190565b60d01c64ffffffff00161792600501917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161051457565b9190820391821161051457565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303612b6557565b7fd663742a0000000000000000000000000000000000000000000000000000000060005260046000fd5b906004116101a35790600490565b90929192836004116101a35783116101a357600401917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0190565b906019116101a35790601990565b90929192836019116101a35783116101a357601901917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe70190565b906015116101a35790601590565b90601b116101a35760150190600690565b9092919283601b116101a35783116101a357601b01917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe50190565b909392938483116101a35784116101a3578101920390565b919091357fffffffff0000000000000000000000000000000000000000000000000000000081169260048110612cc7575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b600401908160041161051457565b600801908160081161051457565b9190820180921161051457565b908210156122725761027b9160051b810190612281565b919091357fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000081169260198110612d6d575050565b7fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000929350829060190360031b1b161690565b94929591612dbb90612db361099e88614604565b928784614689565b60005b828110612e445750505050612e1a82610a7963ffffffff93610a72610a6c610a4773ffffffffffffffffffffffffffffffffffffffff987fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690565b1691167fc36a28045e90a1163d24d4216c8cfd8c44c4e835a486fb84d511d6b9e0736db9600080a3565b612e58610ad2610acc610ac6848789612d22565b90612e67610b06828688612d22565b9092670100000000000000811615612f1057845460a81c60ff169060ff60018184160111610c5657612ea291610ad29060010160ff16610b44565b90612ed4610be7610bde7fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008516610bb9565b610c2c57600193610c21610a6c612f0a947fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690565b01612dbe565b90612f20855460ff9060b01c1690565b9360ff60018187160111610c5657610d13610a6c610a47612f4e95610d06610cbe60019a600160ff91011690565b612f0a565b6000906101b3936040519381855260208501376134fe565b6101b3936040519381855260208501376134fe565b604051903d8252601f19603f3d840101166040523d6000602084013e565b612fa7816130ec565b9081156130d8575b81156130c4575b81156130b0575b811561309c575b8115613088575b8115613074575b8115613060575b811561304c575b8115613038575b8115613024575b8115613010575b8115612fff575090565b63e919a623915063ffffffff161490565b63ffffffff81166352d1902d149150612ff5565b63ffffffff811663d31b575b149150612fee565b63ffffffff811663757c8a26149150612fe7565b63ffffffff8116639cfd7cff149150612fe0565b63ffffffff811663150b7a02149150612fd9565b63ffffffff81166301ffc9a7149150612fd2565b63ffffffff8116631626ba7e149150612fcb565b63ffffffff811663f23a6e61149150612fc4565b63ffffffff811663bc197c81149150612fbd565b63ffffffff81166319822f7c149150612fb6565b63ffffffff811663b0d691fe149150612faf565b6130f58161312c565b908115613118575b8115613107575090565b63f2680c0f915063ffffffff161490565b63ffffffff8116638dd7712f1491506130fd565b63ffffffff1663b61d27f681149081156131be575b81156131b1575b81156131a3575b8115613195575b8115613187575b8115613179575b811561316e575090565b634f1ef28691501490565b635998db5c81149150613164565b63b6b1ccfe8114915061315d565b6393b1dc6181149150613156565b631bbf564c8114915061314f565b621a63e981149150613148565b6334fcd5be81149150613141565b60016115379101614c20565b60401c60048116156131fe5774ffffffffffffffffffffffffffffffffffffffffff1690565b64ffffffffff1690565b8054611537916002019060b01c60ff16614d04565b601f8260209493601f19938186528686013760008582860101520116010190565b611537613297916040519283917fed6dfb13000000000000000000000000000000000000000000000000000000006020840152600060248401523360448401523460648401526080608484015260a4830190600061321d565b03601f198101835282612322565b90611537906132976040519384927fed6dfb13000000000000000000000000000000000000000000000000000000006020850152600060248501523360448501523460648501526080608485015260a484019161321d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146105145760010190565b805160405193926000929091805b61334a57505050825260208201604052565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161337681836123a6565b517fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000081169067040000000000000016156133ea576133b48185614dea565b9067020000000000000081166133cd575b505080613338565b6133e3916133dd91849799614d89565b966132fd565b93386133c5565b6702000000000000008116613401575b5080613338565b6133dd61343a9183969860809063ffffffff6020938060601c835260401c16838201526040808201526000606082015201608081520190565b936133fa565b918215613482577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc01908180845261347757505090565b600401602083013790565b8092506004116101a3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201906134b98261250f565b926134c76040519485612322565b82845236818301116101a3576000926004601c930160208601378301015290565b600091389183602083519301915af1156120e957565b916000923892602083519301915af1156120e957565b74ffffffffffffffffffffffffffffffffffffffffff90606081901c9060401c63ffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000018101613583575060081b74ffffffffffffffffffffffffffffffffffffffff00166004171690565b74ffffffffffffffffffffffffffffffffffffffff00915060081b161690565b8054611537916001019060a81c60ff16614d04565b60009160048210613758576135cd8284612c93565b7f8dd7712f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821614613714575b806136456002847fffffffff0000000000000000000000000000000000000000000000000000000094614fb4565b167fb61d27f60000000000000000000000000000000000000000000000000000000081036136d3575050506004013573ffffffffffffffffffffffffffffffffffffffff165b73ffffffffffffffffffffffffffffffffffffffff1630146136a957565b7f54ff929d0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f34fcd5be00000000000000000000000000000000000000000000000000000000146136fe57505050565b61370e826002936101b395612b9d565b90615076565b5091908061372192612b9d565b90917fffffffff000000000000000000000000000000000000000000000000000000006137516107938486612b8f565b9050613617565b506137666137b39183612c93565b7ffcfc5aad0000000000000000000000000000000000000000000000000000000083527fffffffff0000000000000000000000000000000000000000000000000000000016600452602490565b90fd5b919290926004841061391d576137cc8484612c93565b7f8dd7712f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216146138d7575b8061384384847fffffffff0000000000000000000000000000000000000000000000000000000094614fb4565b167fb61d27f600000000000000000000000000000000000000000000000000000000810361388f575050506004013573ffffffffffffffffffffffffffffffffffffffff16905061368b565b919290917f34fcd5be00000000000000000000000000000000000000000000000000000000146138c0575b50505050565b836138ce9461370e92612b9d565b388080806138ba565b5092806138e49293612b9d565b929091907fffffffff000000000000000000000000000000000000000000000000000000006139166107938686612b8f565b9050613816565b61397861392a8585612c93565b7ffcfc5aad000000000000000000000000000000000000000000000000000000006000527fffffffff0000000000000000000000000000000000000000000000000000000016600452602490565b6000fd5b9081156139b9575060a4601f19601f604060e48501519463ed6dfb1360448201523360848201523485820152608060c48201520193011601815290565b611537915060006132a5565b91908215613a0457505060a4601f19601f604060e48501519463ed6dfb1360448201523360848201523485820152608060c48201520193011601815290565b61153792506132a5565b91908215613a2657505060e46101b3910134306134fe565b6101b392503430612f6b565b613ad490613ac6613a96949360006040519687947f465d33e000000000000000000000000000000000000000000000000000000000602087015282602487015282604487015233606487015234608487015260c060a487015260e48601908361321d565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8584030160c486015261321d565b03601f198101845283612322565b633d6bda32602483015260a060a483015260c482018051601f19019052565b9392613ad492613ac691613a966040519788957f465d33e0000000000000000000000000000000000000000000000000000000006020880152600060248801526000604488015233606488015234608488015260c060a488015260e487019161321d565b909150600063ffffffff8360401c169260601c9183604482015260c481015190826044838301015260406024389301910183855af115613b95575050565b613cd9565b92600091936040602463ffffffff87831c169660601c958760448501528460c48501519182860182806044830152613bea575b505050601f19601f389601160101910183855af115613b95575050565b6064908982601f198616830101520137843880613bcd565b600101600092613c1c826001600052602052604060002090565b5490604051945b600183161580613cd0575b15613c5a576001613c53910192808460051b8801528490600052602052604060002090565b5491613c23565b9250939290506002613c7a613c74835460ff9060b01c1690565b60ff1690565b91019060019160005b828110613c9f57505050506001810160051b8201604052815290565b90919293613cbc6001809201958490600052602052604060002090565b5491828660051b8801520192919092613c83565b50821515613c2e565b604051916018830152601482015263a32d2f5d81526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b6040519160188301526014820152634622c74881526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b6040519160188301526014820152635f85b3b481526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b90604051926018840152601483015281526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b9291633f41826e613297613e1b6080946040519283917fe7db7f7e000000000000000000000000000000000000000000000000000000006020840152602483019960008b5260006044850152336064850152608484015260a483019660a0885260c484019161321d565b945252565b9160ff613e2d8385615301565b3560f81c911690818110613ee95714613e495736926000929190565b91826005116101a3576005600183013560e01c0163ffffffff81116105145763ffffffff1692836005116101a3578084116101a357613ead907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb8501948185612c7b565b9190928415613ebf5760050193929190565b7fb91b669d0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f95c6cb380000000000000000000000000000000000000000000000000000000060005260046000fd5b6000906040601f19601f602095978063ffffffff8a861c169960601c988a6044880152818060c4890152613f8e575b5050011660a4019101845afa15613f57575050565b60405191601883015260148201526346cfe46d81526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b8760e48684168901015260e48701378038613f42565b91909182156122725760ff813560f81c03613fea57826001116101a357600101917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f151d90fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b929092600261406d6140668674ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b809661530a565b945460a01c161561418457601f93929160209182601f1960009784899563ffffffff8a60401c169960601c983060248801528a604488015260a060a4880152818060c489015261416e575b5050011660c4019101845afa601f3d111615614169575050518060201b6101a3577fffffffff00000000000000000000000000000000000000000000000000000000167f1626ba7e0000000000000000000000000000000000000000000000000000000014614145577fffffffff0000000000000000000000000000000000000000000000000000000090565b7f1626ba7e0000000000000000000000000000000000000000000000000000000090565b613d47565b8760e48684168901015260e487013780386140b8565b7fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000847f07391694000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b919091357fffffffffffffffffffffffffffffffffffffffffff000000000000000000000081169260158110614208575050565b7fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000929350829060150360031b1b161690565b919091357fffffffffffff00000000000000000000000000000000000000000000000000008116926006811061426e575050565b7fffffffffffff0000000000000000000000000000000000000000000000000000929350829060060360031b1b161690565b939290916142dd6142c36142bd6142b78487612c21565b906141d4565b60581c90565b74ffffffffffffffffffffffffffffffffffffffffff1690565b9074ffffffffffffffffffffffffffffffffffffffff0482166143408174ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b9260ff614352855460ff9060a81c1690565b166144045782916143638388612c2f565b61436c9161423a565b60d01c988961437c85808b612c40565b9161438693615389565b948161439385808b612c40565b9190946143a290600116151590565b6000149a61141b996143e7996143ce6143e1986115379f986113e8976143d39a6107a2576000926137b6565b615440565b60009080516143ee5761332a565b94612c40565b9030612f53565b905061208e6143fe84808a612c40565b906132a5565b7fd7c794140000000000000000000000000000000000000000000000000000000060005260046000fd5b9291909361448b61448261046d8474ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b9560009561551a565b928551805b6144bf57506144aa9392916144a491613fa4565b9161576b565b9151156144bb5790611537916145ba565b5090565b61451e9295917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6145029201966104c9613c746144fd8a8c51612b19565b612aec565b949093916145166118bb6104e38b8d6123a6565b9384896156a9565b9173ffffffffffffffffffffffffffffffffffffffff83169060018211614552575050869161454c91615742565b95614490565b7fc616f69a000000000000000000000000000000000000000000000000000000006000527fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660045273ffffffffffffffffffffffffffffffffffffffff1660245260446000fd5b90600173ffffffffffffffffffffffffffffffffffffffff6145dc8385615837565b9316036145ea575060011790565b73ffffffffffffffffffffffffffffffffffffffff161790565b74ffffffffffffffffffffffffffffffffffffffffff90604081901c63ffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000018101613583575060581c74ffffffffffffffffffffffffffffffffffffffff00166004171690565b91908110156122725760051b0190565b3561153781610299565b919273ffffffffffffffffffffffffffffffffffffffff6146be845473ffffffffffffffffffffffffffffffffffffffff1690565b7fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000841660181a91606085901c91168061488c575084547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911617845561477c905b84547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1660a09190911b74ff000000000000000000000000000000000000000016178455565b60005b81811061478d575050505050565b6147a061479b82848861466f565b61467f565b6147da610be76147d17fffffffff000000000000000000000000000000000000000000000000000000008416610bb9565b60038801614b4a565b6147e7575060010161477f565b613978906148176118bb7fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000871681565b7fd5d4419e000000000000000000000000000000000000000000000000000000006000527fffffffff000000000000000000000000000000000000000000000000000000009091166004527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016602452604490565b9073ffffffffffffffffffffffffffffffffffffffff16036148b15761477c90614736565b7f50a67a840000000000000000000000000000000000000000000000000000000060005260046000fd5b907fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000061490991168092614b4a565b156149115750565b7f236e22ad0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b91602061153793818152019161321d565b60409073ffffffffffffffffffffffffffffffffffffffff61153794931681528160208201520190610d1d565b9291908161498b575b50509050565b6149b8610be77fb02cc19200000000000000000000000000000000000000000000000000000000866158ea565b614a905773ffffffffffffffffffffffffffffffffffffffff841691823b156101a357614a1892600092836040518096819582947f6d61fe700000000000000000000000000000000000000000000000000000000084526004840161493e565b03925af19081614a75575b50614a6b5750614a31612f80565b90614a676040519283927f1672bd930000000000000000000000000000000000000000000000000000000084526004840161494f565b0390fd5b9050803880614985565b80614a846000614a8a93612322565b806110d7565b38614a23565b7f70560bfc0000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff841660045260246000fd5b92919081614ae25750509050565b6149b8610be77f28171ad000000000000000000000000000000000000000000000000000000000866158ea565b92919081614b1d5750509050565b6149b8610be77fab3e34c100000000000000000000000000000000000000000000000000000000866158ea565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169081158015614c0a575b614c035760016000528060205260406000205480158015614bf9575b15614bd157508181614bcc93614bb6614bc6946001600052602052604060002090565b5590600052602052604060002090565b60019055565b600190565b9180614be7836001600052602052604060002090565b55600052602052604060002055600190565b5060018116614b93565b5050600090565b5081600052806020526040600020541515614b77565b906000600160005282602052604060002054604051915b600182161580614c79575b15614c665760010190808260051b8401526000528360205260406000205490614c37565b6001810160051b83016040528252509150565b50811515614c42565b80518060011c9060005b828110614c995750505050565b80820390828211610514577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116105145781614cdb600193876123a6565b5190614cf2614cea84896123a6565b5191886123a6565b52614cfd82876123a6565b5201614c8c565b614d0d81612345565b91614d1b6040519384612322565b818352601f19614d2a83612345565b01366020850137600060015b838210614d44575050505090565b600052816020526001604060002054917fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008316614d8182886123a6565b520190614d36565b916020928160808263ffffffff601f19601f850116968060601c835260401c16878201526040808201528260608201520192614dcc575b50509060800181520190565b90816040608094600086601f19899716860101523e01013880614dc0565b91906040600063ffffffff83831c169260601c9483602482015260208151910182875af1603f3d11166020600051141692602051937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc13d0185101615614e4e575050565b60405191601883015260148201526374a1a72c81526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b600193926000929181614e985750505050565b9394929373ffffffffffffffffffffffffffffffffffffffff1690813b15614f3557918491614efe93836040518096819582947f8a91b0e3000000000000000000000000000000000000000000000000000000008452602060048501818152019161321d565b03925af19081614f21575b50614f19575090388080806138ba565b9190506138ce565b83614f2e91949294612322565b9138614f09565b8480fd5b600191825b15614f5e575b600092835260208290526040832080549084905592614f3e565b600183161580614f72575b614f4457915050565b50821515614f69565b60031115614f8557565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91614fbe81614f7b565b806150275750610be7614fd1918361597d565b614fd85750565b7fcf7b49f6000000000000000000000000000000000000000000000000000000006000527fffffffff000000000000000000000000000000000000000000000000000000001660045260246000fd5b80615033600192614f7b565b0361504557610be7614fd19183615a5a565b615052610be7828461597d565b9081615061575b50614fd85750565b6150709150610be79083615a5a565b38615059565b9192908201916020818403126101a35780359067ffffffffffffffff82116101a357019180601f840112156101a357823567ffffffffffffffff81116101a3578160208260051b860101116101a357928082037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019060005b8581106150ff5750505050505050565b60208160051b8301013567ffffffffffffffff81116101a357838112156101a3578201602081013573ffffffffffffffffffffffffffffffffffffffff81169081036101a3573014615155575b506001016150ef565b60608101359067ffffffffffffffff82116101a3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1818703018212156101a3570160208101359063ffffffff82116101a3576040019080860382136101a3576004136101a35735908160e01c63b61d27f6811490811561520b575b506136a95761520586897fffffffff0000000000000000000000000000000000000000000000000000000060019516614fb4565b9061514c565b6334fcd5be915014386151d1565b6152709093929361526a8174ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b9061530a565b9263ffffffff8460401c169360601c9230602484015284604484015260c060a48401528060c4840192835193602085019052838501828060448301526152e8575b505050833b156101a3576152db9260206044600094601f19601f389601160101910183865af11590565b6152e3575050565b613d10565b606490600082601f1986168301015201378038806152b1565b90156122725790565b90600482161561534b575060581b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffff00000000000000001790565b5460601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660389190911b6bffffffff0000000000000000161790565b65ffffffffffff60809392604295806040519586378420927f9b23e06584efc6b65fc854cee55011d89f86485487b6db36aed7d23884711ea38552602085015216604083015260608201522060606040517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921881524660208201523060408201522090604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b91817f1626ba7e000000000000000000000000000000000000000000000000000000009461549383615498957fffffffff0000000000000000000000000000000000000000000000000000000097613db1565b614014565b16036154a057565b7f01334f770000000000000000000000000000000000000000000000000000000060005260046000fd5b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156101a357016020813591019167ffffffffffffffff82116101a35781360383136101a357565b61153790615695926040519384927f2a3d428c00000000000000000000000000000000000000000000000000000000602085015260006024850152606060448501526155866084850161556c836101a8565b73ffffffffffffffffffffffffffffffffffffffff169052565b602081013560a48501526156646156586155f96155bc6155a960408601866154ca565b61012060c48b01526101a48a019161321d565b6155c960608601866154ca565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c8a84030160e48b015261321d565b608084013561010488015260a084013561012488015260c084013561014488015261562760e08501856154ca565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c898403016101648a015261321d565b916101008101906154ca565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c8684030161018487015261321d565b90606483015203601f198101835282612322565b90929160006084602092601f19601f63ffffffff8960401c169860601c978960248901528061018489015194858a0182808983015261572c575b5050500116010182840182865af1601f3d1116156157045750505060005190565b6004015163ffffffff16632a3d428c0361572257634db96e31613d7e565b6319aed90d613d7e565b60a49089828886168301015201378038806156e3565b73ffffffffffffffffffffffffffffffffffffffff806157628484615837565b93169116171790565b939260016157c36157bc8774ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b809761530a565b955460a01c16156157e7579384611537949551630ab8785f600483015281526156a9565b7fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000857f566f60e2000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b9061584a8260a01c65ffffffffffff1690565b65ffffffffffff8116156158dd575b65ffffffffffff6158ae61587b6158a761587b849561588661587b8960a01c90565b65ffffffffffff1690565b868116156158d6575b8616908616818111156158ca575060a01b9760d01c90565b9460d01c90565b169116818110156158c1575060d01b1790565b60d01b90501790565b60a01b90509760d01c90565b508561588f565b5065ffffffffffff615859565b6000906020926040517fffffffff00000000000000000000000000000000000000000000000000000000858201927f01ffc9a700000000000000000000000000000000000000000000000000000000845216602482015260248152615950604482612322565b5191617530fa6000513d82615971575b508161596a575090565b9050151590565b60201115915038615960565b9061598a8260e01c6130ec565b9182156159f4575b508161599c575090565b600491506159ea9074ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b5460a01c16151590565b60ff919250615a4e907fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b5460a81c169038615992565b906003615ac87fffffffff000000000000000000000000000000000000000000000000000000009274ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b01911660005260205260406000205415159056fea164736f6c634300081a000a0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0320000000000000000000000000000000000008e6a39e03c7156e46b238c9e2036
Deployed Bytecode
0x60806040526004361015610026575b36156100245761001c61252b565b602081519101f35b005b60003560e01c80621a63e91461014957806301ffc9a714610180578063150b7a021461017b5780631626ba7e1461017657806319822f7c146101715780631bbf564c1461016c57806334fcd5be146101675780634f1ef2861461016257806352d1902d1461015d5780635998db5c14610158578063757c8a26146101535780638dd7712f1461014e57806393b1dc61146101495780639cfd7cff14610144578063b0d691fe1461013f578063b61d27f61461013a578063b6b1ccfe14610135578063bc197c8114610130578063d31b575b1461012b578063e919a62314610126578063f23a6e61146101215763f2680c0f0361000e57611e64565b611dd3565b611b7b565b611ab7565b61193a565b61164b565b61153a565b6114b7565b61143a565b61027f565b611318565b611280565b611162565b6110e2565b610f5f565b610ddc565b610973565b610579565b6103a3565b610312565b6102c3565b73ffffffffffffffffffffffffffffffffffffffff8116036101a357565b600080fd5b35906101b382610185565b565b9181601f840112156101a35782359167ffffffffffffffff83116101a357602083818601950101116101a357565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101a35760043561021981610185565b9160243567ffffffffffffffff81116101a35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82850301126101a357600401916044359067ffffffffffffffff82116101a35761027b916004016101b5565b9091565b346101a357610024610290366101e3565b9291909161209f565b7fffffffff000000000000000000000000000000000000000000000000000000008116036101a357565b346101a35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357602061030860043561030381610299565b6120f5565b6040519015158152f35b346101a35760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35761034c600435610185565b610357602435610185565b60643567ffffffffffffffff81116101a3576103779036906004016101b5565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b346101a35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760243560043567ffffffffffffffff82116101a35761041461040e74ffffffffffffffffffffffffffffffffffffffff049336906004016101b5565b90612a20565b92919390931692610478838261047261046d8874ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b6135a3565b94613db1565b9082515b808015610519577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0191845191820391600183019081116105145782116105145761050f956104cf9260ff165b91613e20565b939296919093966105096104e385896123a6565b517fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690565b86613f13565b61047c565b612abd565b610566610533888661052b8a88613fa4565b929091614014565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681529081906020820190565b0390f35b90816101209103126101a35790565b346101a35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a3576105cb61064a91369060040161056a565b602435604435916105da612b26565b60009060208101356105eb816131d8565b6105f9610100840184612281565b81929192819461060b84600216151590565b6107aa575b50505061065760608501916106258387612281565b74ffffffffffffffffffffffffffffffffffffffff04839293169b8c92600116151590565b156107a2576000926137b6565b60ff6106b06106a68a74ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b5460b01c60ff1690565b1615159081610739575b5061070f576105669686956106ce9461442e565b90801561070857906106df916145ba565b915b6106f7575b506040519081529081906020820190565b60009081803892335af150386106e6565b50916106e1565b7f5f49f00a0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f8dd7712f00000000000000000000000000000000000000000000000000000000915061079961079361078d7fffffffff000000000000000000000000000000000000000000000000000000009388612281565b90612b8f565b90612c93565b161415386106ba565b6001926137b6565b65ffffffffffff97508293955061087c94506108769061084c6108706107ea6107e16107db61079389899a99612b8f565b60e01c90565b63ffffffff1690565b9a8b9361086961086388876108578c6108346107e16107db61079361081861081188612cf9565b8987612b9d565b98909761082d61082782612cf9565b91612d07565b9187612c7b565b9a8d6108518d61084c61084685612d07565b94612d07565b612d15565b92612c7b565b929091604051966142a0565b91604052565b1660a01b90565b99612d07565b91612c7b565b91388080610610565b9181601f840112156101a35782359167ffffffffffffffff83116101a3576020808501948460051b0101116101a357565b9060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126101a3576004357fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000811681036101a3579160243567ffffffffffffffff81116101a3578161092d91600401610885565b9290929160443567ffffffffffffffff81116101a35781610950916004016101b5565b929092916064359067ffffffffffffffff82116101a35761027b91600401610885565b346101a357610981366108b6565b90919293946109ec61099161261c565b966109e461099e8a614604565b74ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b928984614689565b60005b828110610ab257610024878773ffffffffffffffffffffffffffffffffffffffff63ffffffff610a858d610a798c610a72610a6c7fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000085165b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690565b60601c90565b9687614b0f565b60401c63ffffffff1690565b1691167fc36a28045e90a1163d24d4216c8cfd8c44c4e835a486fb84d511d6b9e0736db9600080a361295f565b610af7610ad2610acc610ac6848789612d22565b90612bd8565b90612d39565b7fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690565b90610b0d610b06828688612d22565b8091612be6565b9092670100000000000000811615610c8057845460a81c60ff169060ff60018184160111610c5657610b8b91610ad29060010160ff165b87547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1660a89190911b75ff00000000000000000000000000000000000000000016178755565b90610beb610be7610bde7fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000085165b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690565b60018801614b4a565b1590565b610c2c57600193610c21610a6c610c26947fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690565b614ad4565b016109ef565b7f298ac3da0000000000000000000000000000000000000000000000000000000060005260046000fd5b7fe330dd260000000000000000000000000000000000000000000000000000000060005260046000fd5b90610c90855460ff9060b01c1690565b9360ff60018187160111610c5657610d13610a6c610a47610d1895610d06610cbe60019a600160ff91011690565b8b547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1660b09190911b76ff0000000000000000000000000000000000000000000016178b55565b610ad28160028c016148db565b61497c565b610c26565b919082519283825260005b848110610d49575050601f19601f8460006020809697860101520116010190565b80602080928401015182828601015201610d28565b602081016020825282518091526040820191602060408360051b8301019401926000915b838310610d9157505050505090565b9091929394602080610dcd837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528951610d1d565b97019301930191939290610d82565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a357610e26903690600401610885565b610e2e61261c565b6060337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03273ffffffffffffffffffffffffffffffffffffffff1614610f0b5750610e778261235d565b9160005b818110610e9e5750506105669250610e929061295f565b60405191829182610d5e565b80610ee7610eb7610eb2600194868a612232565b612277565b6020610ec484878b612232565b013590610edf610ed585888c612232565b6040810190612281565b929091612f6b565b610eef612f80565b610ef982876123a6565b52610f0481866123a6565b5001610e7b565b91909260005b828110610f2757505050610e926105669261295f565b80610f59610f3b610eb26001948787612232565b6020610f48848888612232565b013590610edf610ed5858989612232565b01610f11565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357600435610f9581610185565b60243567ffffffffffffffff81116101a357610fb59036906004016101b5565b919091307f00000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f146110c957610fe761261c565b9073ffffffffffffffffffffffffffffffffffffffff60009316906352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc602060016004601d865afa51036110bb57817fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8580a280827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55611097575b836110948461295f565b80f35b908184926040519687378538925af4156110b257828061108a565b503d90823e3d90fd5b6355299b496001526004601dfd5b639f03a0266000526004601cfd5b60009103126101a357565b346101a35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357307f00000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f036110c95760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043560243567ffffffffffffffff81116101a3576111af9036906004016101b5565b906044359283151584036101a3576064356111c861261c565b94846040519485376001146112215750f05b8015611213576111ec6105669261295f565b60405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b637e16b8cd6000526004601cfd5b929190f56111da565b906020808351928381520192019060005b8181106112485750505090565b82517fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001684526020938401939092019160010161123b565b346101a35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760606112c56004356112c081610299565b6123ba565b6105666040519283926020845273ffffffffffffffffffffffffffffffffffffffff81511660208501526020810151151560408501526040810151151582850152015160808084015260a083019061122a565b346101a35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a35761136a61002491369060040161056a565b611372612b26565b61141b6114156113ed6113e874ffffffffffffffffffffffffffffffffffffffff046113a160208701356131d8565b1674ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b613208565b6000908051611420575b6114048261140f9261332a565b946060810190612281565b91613440565b306134e8565b61295f565b905061140f6114046114313661323e565b929150506113f7565b346101a35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357610566604080519061147b8183612322565b601d82527f616c6368656d792e6d6f64756c61722d6163636f756e742e322e302e30000000602083015251918291602083526020830190610d1d565b346101a35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032168152f35b906020611537928181520190610d1d565b90565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043561157081610185565b6044359060243567ffffffffffffffff83116101a3576115ac61159a6105669436906004016101b5565b906115a361261c565b93606095612f6b565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032163303611607575b6115f39061295f565b604051918291602083526020830190610d1d565b90506115f3611614612f80565b9190506115ea565b600435907fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000821682036101a357565b346101a35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35761168261161c565b60243567ffffffffffffffff81116101a3576116a29036906004016101b5565b9060443567ffffffffffffffff81116101a3576116c3903690600401610885565b90926116cd61261c565b936116da61099e87613514565b90600193806117e9575b50506100249561173d826116fd60016117529501614f39565b61170960028201614f39565b61171560038201614f39565b80547fffffffffffffffffff0000000000000000000000000000000000000000000000169055565b606081901c9160409190911c63ffffffff1690565b919093836117ae575b5050604051911515825263ffffffff169173ffffffffffffffffffffffffffffffffffffffff16907f43f7309d11ba6b2e180e9ab8a6da09d2fa1f585d7daed4b26c1c7f2a90b867a290602090a361295f565b7f43f7309d11ba6b2e180e9ab8a6da09d2fa1f585d7daed4b26c1c7f2a90b867a292935063ffffffff916117e29186614e85565b929161175b565b6117f283613208565b6117fb846135a3565b916118098351835190612d15565b810361191057919290600093805185915b81831061188f575050508051926000925b84841061183b57505050506116e4565b9091929394976118726001916118528b8686612d22565b90611863610a6c6104e38b8b6123a6565b8361187d575b505050996132fd565b95940192919061182b565b6118879350614e85565b388080611869565b909194929395986118f06001916118a78c878b612d22565b906118e061173d6118bb6104e38d8a6123a6565b7fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690565b50836118fe575b5050509a6132fd565b95019190959392949561181a565b6119089350614e85565b3880806118e7565b7fa24a13a60000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357611974600435610185565b61197f602435610185565b60443567ffffffffffffffff81116101a35761199f903690600401610885565b505060643567ffffffffffffffff81116101a3576119c1903690600401610885565b505060843567ffffffffffffffff81116101a3576119e39036906004016101b5565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b906020825260ff81511660208301526060611a52611a3d60208401516080604087015260a086019061122a565b6040840151601f19868303018487015261122a565b910151916080601f19828403019101526020808351928381520192019060005b818110611a7f5750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611a72565b346101a35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357610566611af161161c565b60405190611afe82612301565b60008252611b64600360208401606081526040850160608152611b4a611b2e61099e606089019760608952613514565b9260ff845460a01c168852611b42846135a3565b809152614c82565b611b5382613208565b90611b5d82614c82565b5201614c20565b90611b6e82614c82565b5260405191829182611a10565b346101a357611b89366108b6565b7f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0054969590949193919067ffffffffffffffff611bd660ff60408b901c16159967ffffffffffffffff1690565b1680159081611dcb575b6001149081611dc1575b159081611db8575b50611d8e57611c739688611c6a60017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000007f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd005416177f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0055565b611d1357612d9f565b611c7957005b611ce47fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0054167f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0055565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b611d89680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd005416177f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd0055565b612d9f565b7ff92ee8a90000000000000000000000000000000000000000000000000000000060005260046000fd5b90501538611bf2565b303b159150611bea565b899150611be0565b346101a35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a357611e0d600435610185565b611e18602435610185565b60843567ffffffffffffffff81116101a357611e389036906004016101b5565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a35760043567ffffffffffffffff81116101a357611eae9036906004016101b5565b60243567ffffffffffffffff81116101a35761040e611ed19136906004016101b5565b74ffffffffffffffffffffffffffffffffffffffff04839592931694611f43611f3a8774ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b91600116151590565b156120945790611f5760005b8787866137b6565b8094611fb38592611fab61046d8a74ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b968387613af3565b9385515b808015612029577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01938751918203916001830190811161051457821161051457612022986120089260ff166104c9565b9692999190969961201c6104e3888c6123a6565b89613b9a565b9392611fb7565b505061205e61205086956113e8610566988c6120488d6120649a613fa4565b929091615219565b60009080516120815761332a565b93613a0e565b61207561206f612f80565b9161295f565b60405191829182611526565b905061208e8484886139c5565b9061332a565b90611f576001611f4f565b505050506120ab61261c565b600060405136828237389036907f0000000000000000000000000000000000008e6a39e03c7156e46b238c9e20365af4156120e9576101b39061295f565b6040513d6000823e3d90fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167fffffffff0000000000000000000000000000000000000000000000000000000081146121fd577f150b7a0200000000000000000000000000000000000000000000000000000000811480156121d4575b80156121ab575b6121a5576000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd03602052604060002054151590565b50600190565b507f01ffc9a700000000000000000000000000000000000000000000000000000000811461216f565b507f4e2312e0000000000000000000000000000000000000000000000000000000008114612168565b50600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91908110156122725760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1813603018212156101a3570190565b612203565b3561153781610185565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101a3570180359067ffffffffffffffff82116101a3576020019181360383136101a357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6080810190811067ffffffffffffffff82111761231d57604052565b6122d2565b90601f601f19910116810190811067ffffffffffffffff82111761231d57604052565b67ffffffffffffffff811161231d5760051b60200190565b9061236782612345565b6123746040519182612322565b828152601f196123848294612345565b019060005b82811061239557505050565b806060602080938501015201612389565b80518210156122725760209160051b010190565b90604051916123c883612301565b60008352600060208401526000604084015260608084015282612436827fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b9160e01c61244381612f9e565b1561249a57610be78161246e61245b612473946130ec565b3086528015602087015215156040860152565b61312c565b61249557506001612485915b01614c20565b61248e81614c82565b6060830152565b925050565b508161250a600192604061250361248596546124e66124cc8273ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168552565b6124fa60a082901c60ff1615156020860152565b60a81c60ff1690565b1515910152565b61247f565b67ffffffffffffffff811161231d57601f01601f191660200190565b7fffffffff000000000000000000000000000000000000000000000000000000006000351673ffffffffffffffffffffffffffffffffffffffff6125ba827fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b54169081156125ef57506125e46125cf61261c565b916040519036825236600060208401376134e8565b61153761206f612f80565b7ffcfc5aad0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321633141580612955575b806128c6575b1561283b573360081b74ffffffffffffffffffffffffffffffffffffffff00166004179161269383366135b8565b6126e061046d8474ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b92835180612829575b805b6127e757506115379293506127c3906127bd6127767fffffffff00000000000000000000000000000000000000000000000000000000600035167fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b9174ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b90613c02565b60009181516127d3575b5061332a565b6127e0919250369061397c565b90386127cd565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0193846128223661281c6104e384866123a6565b86613b57565b90946126eb565b91506128353636613a32565b916126e9565b90611537906128c16128bc7fffffffff00000000000000000000000000000000000000000000000000000000600035167fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b6131cc565b6127c3565b50612950610be76129467fffffffff00000000000000000000000000000000000000000000000000000000600035167fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b5460a01c60ff1690565b612665565b503033141561265f565b601f19815191019060005b81811061297657505050565b8251809303928351601f196000602087015193635d413a8188527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4389101601c890183865af1950194156129ce57505060010161296a565b604051916018830152601482015263f19fc59381526040808201523d60608201523d612a06575b601c601f19601f3d01166064019101fd5b60006080601f193d16830101523d6000608083013e6129f5565b91600582106101a35782358060f81c9060048216600014612a8857601584106101a35760501c74ffffffffffffffffffffffffffffffffffffffff00161792601501917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb0190565b60d01c64ffffffff00161792600501917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161051457565b9190820391821161051457565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032163303612b6557565b7fd663742a0000000000000000000000000000000000000000000000000000000060005260046000fd5b906004116101a35790600490565b90929192836004116101a35783116101a357600401917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0190565b906019116101a35790601990565b90929192836019116101a35783116101a357601901917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe70190565b906015116101a35790601590565b90601b116101a35760150190600690565b9092919283601b116101a35783116101a357601b01917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe50190565b909392938483116101a35784116101a3578101920390565b919091357fffffffff0000000000000000000000000000000000000000000000000000000081169260048110612cc7575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b600401908160041161051457565b600801908160081161051457565b9190820180921161051457565b908210156122725761027b9160051b810190612281565b919091357fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000081169260198110612d6d575050565b7fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000929350829060190360031b1b161690565b94929591612dbb90612db361099e88614604565b928784614689565b60005b828110612e445750505050612e1a82610a7963ffffffff93610a72610a6c610a4773ffffffffffffffffffffffffffffffffffffffff987fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690565b1691167fc36a28045e90a1163d24d4216c8cfd8c44c4e835a486fb84d511d6b9e0736db9600080a3565b612e58610ad2610acc610ac6848789612d22565b90612e67610b06828688612d22565b9092670100000000000000811615612f1057845460a81c60ff169060ff60018184160111610c5657612ea291610ad29060010160ff16610b44565b90612ed4610be7610bde7fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008516610bb9565b610c2c57600193610c21610a6c612f0a947fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690565b01612dbe565b90612f20855460ff9060b01c1690565b9360ff60018187160111610c5657610d13610a6c610a47612f4e95610d06610cbe60019a600160ff91011690565b612f0a565b6000906101b3936040519381855260208501376134fe565b6101b3936040519381855260208501376134fe565b604051903d8252601f19603f3d840101166040523d6000602084013e565b612fa7816130ec565b9081156130d8575b81156130c4575b81156130b0575b811561309c575b8115613088575b8115613074575b8115613060575b811561304c575b8115613038575b8115613024575b8115613010575b8115612fff575090565b63e919a623915063ffffffff161490565b63ffffffff81166352d1902d149150612ff5565b63ffffffff811663d31b575b149150612fee565b63ffffffff811663757c8a26149150612fe7565b63ffffffff8116639cfd7cff149150612fe0565b63ffffffff811663150b7a02149150612fd9565b63ffffffff81166301ffc9a7149150612fd2565b63ffffffff8116631626ba7e149150612fcb565b63ffffffff811663f23a6e61149150612fc4565b63ffffffff811663bc197c81149150612fbd565b63ffffffff81166319822f7c149150612fb6565b63ffffffff811663b0d691fe149150612faf565b6130f58161312c565b908115613118575b8115613107575090565b63f2680c0f915063ffffffff161490565b63ffffffff8116638dd7712f1491506130fd565b63ffffffff1663b61d27f681149081156131be575b81156131b1575b81156131a3575b8115613195575b8115613187575b8115613179575b811561316e575090565b634f1ef28691501490565b635998db5c81149150613164565b63b6b1ccfe8114915061315d565b6393b1dc6181149150613156565b631bbf564c8114915061314f565b621a63e981149150613148565b6334fcd5be81149150613141565b60016115379101614c20565b60401c60048116156131fe5774ffffffffffffffffffffffffffffffffffffffffff1690565b64ffffffffff1690565b8054611537916002019060b01c60ff16614d04565b601f8260209493601f19938186528686013760008582860101520116010190565b611537613297916040519283917fed6dfb13000000000000000000000000000000000000000000000000000000006020840152600060248401523360448401523460648401526080608484015260a4830190600061321d565b03601f198101835282612322565b90611537906132976040519384927fed6dfb13000000000000000000000000000000000000000000000000000000006020850152600060248501523360448501523460648501526080608485015260a484019161321d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146105145760010190565b805160405193926000929091805b61334a57505050825260208201604052565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161337681836123a6565b517fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000081169067040000000000000016156133ea576133b48185614dea565b9067020000000000000081166133cd575b505080613338565b6133e3916133dd91849799614d89565b966132fd565b93386133c5565b6702000000000000008116613401575b5080613338565b6133dd61343a9183969860809063ffffffff6020938060601c835260401c16838201526040808201526000606082015201608081520190565b936133fa565b918215613482577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc01908180845261347757505090565b600401602083013790565b8092506004116101a3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201906134b98261250f565b926134c76040519485612322565b82845236818301116101a3576000926004601c930160208601378301015290565b600091389183602083519301915af1156120e957565b916000923892602083519301915af1156120e957565b74ffffffffffffffffffffffffffffffffffffffffff90606081901c9060401c63ffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000018101613583575060081b74ffffffffffffffffffffffffffffffffffffffff00166004171690565b74ffffffffffffffffffffffffffffffffffffffff00915060081b161690565b8054611537916001019060a81c60ff16614d04565b60009160048210613758576135cd8284612c93565b7f8dd7712f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821614613714575b806136456002847fffffffff0000000000000000000000000000000000000000000000000000000094614fb4565b167fb61d27f60000000000000000000000000000000000000000000000000000000081036136d3575050506004013573ffffffffffffffffffffffffffffffffffffffff165b73ffffffffffffffffffffffffffffffffffffffff1630146136a957565b7f54ff929d0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f34fcd5be00000000000000000000000000000000000000000000000000000000146136fe57505050565b61370e826002936101b395612b9d565b90615076565b5091908061372192612b9d565b90917fffffffff000000000000000000000000000000000000000000000000000000006137516107938486612b8f565b9050613617565b506137666137b39183612c93565b7ffcfc5aad0000000000000000000000000000000000000000000000000000000083527fffffffff0000000000000000000000000000000000000000000000000000000016600452602490565b90fd5b919290926004841061391d576137cc8484612c93565b7f8dd7712f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216146138d7575b8061384384847fffffffff0000000000000000000000000000000000000000000000000000000094614fb4565b167fb61d27f600000000000000000000000000000000000000000000000000000000810361388f575050506004013573ffffffffffffffffffffffffffffffffffffffff16905061368b565b919290917f34fcd5be00000000000000000000000000000000000000000000000000000000146138c0575b50505050565b836138ce9461370e92612b9d565b388080806138ba565b5092806138e49293612b9d565b929091907fffffffff000000000000000000000000000000000000000000000000000000006139166107938686612b8f565b9050613816565b61397861392a8585612c93565b7ffcfc5aad000000000000000000000000000000000000000000000000000000006000527fffffffff0000000000000000000000000000000000000000000000000000000016600452602490565b6000fd5b9081156139b9575060a4601f19601f604060e48501519463ed6dfb1360448201523360848201523485820152608060c48201520193011601815290565b611537915060006132a5565b91908215613a0457505060a4601f19601f604060e48501519463ed6dfb1360448201523360848201523485820152608060c48201520193011601815290565b61153792506132a5565b91908215613a2657505060e46101b3910134306134fe565b6101b392503430612f6b565b613ad490613ac6613a96949360006040519687947f465d33e000000000000000000000000000000000000000000000000000000000602087015282602487015282604487015233606487015234608487015260c060a487015260e48601908361321d565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8584030160c486015261321d565b03601f198101845283612322565b633d6bda32602483015260a060a483015260c482018051601f19019052565b9392613ad492613ac691613a966040519788957f465d33e0000000000000000000000000000000000000000000000000000000006020880152600060248801526000604488015233606488015234608488015260c060a488015260e487019161321d565b909150600063ffffffff8360401c169260601c9183604482015260c481015190826044838301015260406024389301910183855af115613b95575050565b613cd9565b92600091936040602463ffffffff87831c169660601c958760448501528460c48501519182860182806044830152613bea575b505050601f19601f389601160101910183855af115613b95575050565b6064908982601f198616830101520137843880613bcd565b600101600092613c1c826001600052602052604060002090565b5490604051945b600183161580613cd0575b15613c5a576001613c53910192808460051b8801528490600052602052604060002090565b5491613c23565b9250939290506002613c7a613c74835460ff9060b01c1690565b60ff1690565b91019060019160005b828110613c9f57505050506001810160051b8201604052815290565b90919293613cbc6001809201958490600052602052604060002090565b5491828660051b8801520192919092613c83565b50821515613c2e565b604051916018830152601482015263a32d2f5d81526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b6040519160188301526014820152634622c74881526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b6040519160188301526014820152635f85b3b481526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b90604051926018840152601483015281526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b9291633f41826e613297613e1b6080946040519283917fe7db7f7e000000000000000000000000000000000000000000000000000000006020840152602483019960008b5260006044850152336064850152608484015260a483019660a0885260c484019161321d565b945252565b9160ff613e2d8385615301565b3560f81c911690818110613ee95714613e495736926000929190565b91826005116101a3576005600183013560e01c0163ffffffff81116105145763ffffffff1692836005116101a3578084116101a357613ead907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb8501948185612c7b565b9190928415613ebf5760050193929190565b7fb91b669d0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f95c6cb380000000000000000000000000000000000000000000000000000000060005260046000fd5b6000906040601f19601f602095978063ffffffff8a861c169960601c988a6044880152818060c4890152613f8e575b5050011660a4019101845afa15613f57575050565b60405191601883015260148201526346cfe46d81526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b8760e48684168901015260e48701378038613f42565b91909182156122725760ff813560f81c03613fea57826001116101a357600101917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f151d90fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b929092600261406d6140668674ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b809661530a565b945460a01c161561418457601f93929160209182601f1960009784899563ffffffff8a60401c169960601c983060248801528a604488015260a060a4880152818060c489015261416e575b5050011660c4019101845afa601f3d111615614169575050518060201b6101a3577fffffffff00000000000000000000000000000000000000000000000000000000167f1626ba7e0000000000000000000000000000000000000000000000000000000014614145577fffffffff0000000000000000000000000000000000000000000000000000000090565b7f1626ba7e0000000000000000000000000000000000000000000000000000000090565b613d47565b8760e48684168901015260e487013780386140b8565b7fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000847f07391694000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b919091357fffffffffffffffffffffffffffffffffffffffffff000000000000000000000081169260158110614208575050565b7fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000929350829060150360031b1b161690565b919091357fffffffffffff00000000000000000000000000000000000000000000000000008116926006811061426e575050565b7fffffffffffff0000000000000000000000000000000000000000000000000000929350829060060360031b1b161690565b939290916142dd6142c36142bd6142b78487612c21565b906141d4565b60581c90565b74ffffffffffffffffffffffffffffffffffffffffff1690565b9074ffffffffffffffffffffffffffffffffffffffff0482166143408174ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b9260ff614352855460ff9060a81c1690565b166144045782916143638388612c2f565b61436c9161423a565b60d01c988961437c85808b612c40565b9161438693615389565b948161439385808b612c40565b9190946143a290600116151590565b6000149a61141b996143e7996143ce6143e1986115379f986113e8976143d39a6107a2576000926137b6565b615440565b60009080516143ee5761332a565b94612c40565b9030612f53565b905061208e6143fe84808a612c40565b906132a5565b7fd7c794140000000000000000000000000000000000000000000000000000000060005260046000fd5b9291909361448b61448261046d8474ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b9560009561551a565b928551805b6144bf57506144aa9392916144a491613fa4565b9161576b565b9151156144bb5790611537916145ba565b5090565b61451e9295917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6145029201966104c9613c746144fd8a8c51612b19565b612aec565b949093916145166118bb6104e38b8d6123a6565b9384896156a9565b9173ffffffffffffffffffffffffffffffffffffffff83169060018211614552575050869161454c91615742565b95614490565b7fc616f69a000000000000000000000000000000000000000000000000000000006000527fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660045273ffffffffffffffffffffffffffffffffffffffff1660245260446000fd5b90600173ffffffffffffffffffffffffffffffffffffffff6145dc8385615837565b9316036145ea575060011790565b73ffffffffffffffffffffffffffffffffffffffff161790565b74ffffffffffffffffffffffffffffffffffffffffff90604081901c63ffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000018101613583575060581c74ffffffffffffffffffffffffffffffffffffffff00166004171690565b91908110156122725760051b0190565b3561153781610299565b919273ffffffffffffffffffffffffffffffffffffffff6146be845473ffffffffffffffffffffffffffffffffffffffff1690565b7fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000841660181a91606085901c91168061488c575084547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911617845561477c905b84547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1660a09190911b74ff000000000000000000000000000000000000000016178455565b60005b81811061478d575050505050565b6147a061479b82848861466f565b61467f565b6147da610be76147d17fffffffff000000000000000000000000000000000000000000000000000000008416610bb9565b60038801614b4a565b6147e7575060010161477f565b613978906148176118bb7fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000871681565b7fd5d4419e000000000000000000000000000000000000000000000000000000006000527fffffffff000000000000000000000000000000000000000000000000000000009091166004527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016602452604490565b9073ffffffffffffffffffffffffffffffffffffffff16036148b15761477c90614736565b7f50a67a840000000000000000000000000000000000000000000000000000000060005260046000fd5b907fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000061490991168092614b4a565b156149115750565b7f236e22ad0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b91602061153793818152019161321d565b60409073ffffffffffffffffffffffffffffffffffffffff61153794931681528160208201520190610d1d565b9291908161498b575b50509050565b6149b8610be77fb02cc19200000000000000000000000000000000000000000000000000000000866158ea565b614a905773ffffffffffffffffffffffffffffffffffffffff841691823b156101a357614a1892600092836040518096819582947f6d61fe700000000000000000000000000000000000000000000000000000000084526004840161493e565b03925af19081614a75575b50614a6b5750614a31612f80565b90614a676040519283927f1672bd930000000000000000000000000000000000000000000000000000000084526004840161494f565b0390fd5b9050803880614985565b80614a846000614a8a93612322565b806110d7565b38614a23565b7f70560bfc0000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff841660045260246000fd5b92919081614ae25750509050565b6149b8610be77f28171ad000000000000000000000000000000000000000000000000000000000866158ea565b92919081614b1d5750509050565b6149b8610be77fab3e34c100000000000000000000000000000000000000000000000000000000866158ea565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169081158015614c0a575b614c035760016000528060205260406000205480158015614bf9575b15614bd157508181614bcc93614bb6614bc6946001600052602052604060002090565b5590600052602052604060002090565b60019055565b600190565b9180614be7836001600052602052604060002090565b55600052602052604060002055600190565b5060018116614b93565b5050600090565b5081600052806020526040600020541515614b77565b906000600160005282602052604060002054604051915b600182161580614c79575b15614c665760010190808260051b8401526000528360205260406000205490614c37565b6001810160051b83016040528252509150565b50811515614c42565b80518060011c9060005b828110614c995750505050565b80820390828211610514577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116105145781614cdb600193876123a6565b5190614cf2614cea84896123a6565b5191886123a6565b52614cfd82876123a6565b5201614c8c565b614d0d81612345565b91614d1b6040519384612322565b818352601f19614d2a83612345565b01366020850137600060015b838210614d44575050505090565b600052816020526001604060002054917fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008316614d8182886123a6565b520190614d36565b916020928160808263ffffffff601f19601f850116968060601c835260401c16878201526040808201528260608201520192614dcc575b50509060800181520190565b90816040608094600086601f19899716860101523e01013880614dc0565b91906040600063ffffffff83831c169260601c9483602482015260208151910182875af1603f3d11166020600051141692602051937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc13d0185101615614e4e575050565b60405191601883015260148201526374a1a72c81526040808201523d60608201523d612a0657601c601f19601f3d01166064019101fd5b600193926000929181614e985750505050565b9394929373ffffffffffffffffffffffffffffffffffffffff1690813b15614f3557918491614efe93836040518096819582947f8a91b0e3000000000000000000000000000000000000000000000000000000008452602060048501818152019161321d565b03925af19081614f21575b50614f19575090388080806138ba565b9190506138ce565b83614f2e91949294612322565b9138614f09565b8480fd5b600191825b15614f5e575b600092835260208290526040832080549084905592614f3e565b600183161580614f72575b614f4457915050565b50821515614f69565b60031115614f8557565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91614fbe81614f7b565b806150275750610be7614fd1918361597d565b614fd85750565b7fcf7b49f6000000000000000000000000000000000000000000000000000000006000527fffffffff000000000000000000000000000000000000000000000000000000001660045260246000fd5b80615033600192614f7b565b0361504557610be7614fd19183615a5a565b615052610be7828461597d565b9081615061575b50614fd85750565b6150709150610be79083615a5a565b38615059565b9192908201916020818403126101a35780359067ffffffffffffffff82116101a357019180601f840112156101a357823567ffffffffffffffff81116101a3578160208260051b860101116101a357928082037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019060005b8581106150ff5750505050505050565b60208160051b8301013567ffffffffffffffff81116101a357838112156101a3578201602081013573ffffffffffffffffffffffffffffffffffffffff81169081036101a3573014615155575b506001016150ef565b60608101359067ffffffffffffffff82116101a3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1818703018212156101a3570160208101359063ffffffff82116101a3576040019080860382136101a3576004136101a35735908160e01c63b61d27f6811490811561520b575b506136a95761520586897fffffffff0000000000000000000000000000000000000000000000000000000060019516614fb4565b9061514c565b6334fcd5be915014386151d1565b6152709093929361526a8174ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b9061530a565b9263ffffffff8460401c169360601c9230602484015284604484015260c060a48401528060c4840192835193602085019052838501828060448301526152e8575b505050833b156101a3576152db9260206044600094601f19601f389601160101910183865af11590565b6152e3575050565b613d10565b606490600082601f1986168301015201378038806152b1565b90156122725790565b90600482161561534b575060581b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffff00000000000000001790565b5460601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660389190911b6bffffffff0000000000000000161790565b65ffffffffffff60809392604295806040519586378420927f9b23e06584efc6b65fc854cee55011d89f86485487b6db36aed7d23884711ea38552602085015216604083015260608201522060606040517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921881524660208201523060408201522090604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b91817f1626ba7e000000000000000000000000000000000000000000000000000000009461549383615498957fffffffff0000000000000000000000000000000000000000000000000000000097613db1565b614014565b16036154a057565b7f01334f770000000000000000000000000000000000000000000000000000000060005260046000fd5b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156101a357016020813591019167ffffffffffffffff82116101a35781360383136101a357565b61153790615695926040519384927f2a3d428c00000000000000000000000000000000000000000000000000000000602085015260006024850152606060448501526155866084850161556c836101a8565b73ffffffffffffffffffffffffffffffffffffffff169052565b602081013560a48501526156646156586155f96155bc6155a960408601866154ca565b61012060c48b01526101a48a019161321d565b6155c960608601866154ca565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c8a84030160e48b015261321d565b608084013561010488015260a084013561012488015260c084013561014488015261562760e08501856154ca565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c898403016101648a015261321d565b916101008101906154ca565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c8684030161018487015261321d565b90606483015203601f198101835282612322565b90929160006084602092601f19601f63ffffffff8960401c169860601c978960248901528061018489015194858a0182808983015261572c575b5050500116010182840182865af1601f3d1116156157045750505060005190565b6004015163ffffffff16632a3d428c0361572257634db96e31613d7e565b6319aed90d613d7e565b60a49089828886168301015201378038806156e3565b73ffffffffffffffffffffffffffffffffffffffff806157628484615837565b93169116171790565b939260016157c36157bc8774ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b809761530a565b955460a01c16156157e7579384611537949551630ab8785f600483015281526156a9565b7fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000857f566f60e2000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b9061584a8260a01c65ffffffffffff1690565b65ffffffffffff8116156158dd575b65ffffffffffff6158ae61587b6158a761587b849561588661587b8960a01c90565b65ffffffffffff1690565b868116156158d6575b8616908616818111156158ca575060a01b9760d01c90565b9460d01c90565b169116818110156158c1575060d01b1790565b60d01b90501790565b60a01b90509760d01c90565b508561588f565b5065ffffffffffff615859565b6000906020926040517fffffffff00000000000000000000000000000000000000000000000000000000858201927f01ffc9a700000000000000000000000000000000000000000000000000000000845216602482015260248152615950604482612322565b5191617530fa6000513d82615971575b508161596a575090565b9050151590565b60201115915038615960565b9061598a8260e01c6130ec565b9182156159f4575b508161599c575090565b600491506159ea9074ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b5460a01c16151590565b60ff919250615a4e907fffffffff00000000000000000000000000000000000000000000000000000000166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd01602052604060002090565b5460a81c169038615992565b906003615ac87fffffffff000000000000000000000000000000000000000000000000000000009274ffffffffffffffffffffffffffffffffffffffffff166000527f596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd02602052604060002090565b01911660005260205260406000205415159056fea164736f6c634300081a000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0320000000000000000000000000000000000008e6a39e03c7156e46b238c9e2036
-----Decoded View---------------
Arg [0] : entryPoint (address): 0x0000000071727De22E5E9d8BAf0edAc6f37da032
Arg [1] : executionInstallDelegate (address): 0x0000000000008e6a39E03C7156e46b238C9E2036
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Arg [1] : 0000000000000000000000000000000000008e6a39e03c7156e46b238c9e2036
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.