Source Code
Overview
S Balance
0 S
More Info
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
6528094 | 46 hrs ago | Contract Creation | 0 S |
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:
Nexus
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 999 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { UUPSUpgradeable } from "solady/utils/UUPSUpgradeable.sol"; import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; import { ExecLib } from "./lib/ExecLib.sol"; import { INexus } from "./interfaces/INexus.sol"; import { BaseAccount } from "./base/BaseAccount.sol"; import { IERC7484 } from "./interfaces/IERC7484.sol"; import { ModuleManager } from "./base/ModuleManager.sol"; import { ExecutionHelper } from "./base/ExecutionHelper.sol"; import { IValidator } from "./interfaces/modules/IValidator.sol"; import { MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK, MODULE_TYPE_HOOK, MODULE_TYPE_MULTI, SUPPORTS_ERC7739 } from "./types/Constants.sol"; import { ModeLib, ExecutionMode, ExecType, CallType, CALLTYPE_BATCH, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL, EXECTYPE_DEFAULT, EXECTYPE_TRY } from "./lib/ModeLib.sol"; import { NonceLib } from "./lib/NonceLib.sol"; import { SentinelListLib, SENTINEL, ZERO_ADDRESS } from "sentinellist/SentinelList.sol"; /// @title Nexus - Smart Account /// @notice This contract integrates various functionalities to handle modular smart accounts compliant with ERC-7579 and ERC-4337 standards. /// @dev Comprehensive suite of methods for managing smart accounts, integrating module management, execution management, and upgradability via UUPS. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady contract Nexus is INexus, BaseAccount, ExecutionHelper, ModuleManager, UUPSUpgradeable { using ModeLib for ExecutionMode; using ExecLib for bytes; using NonceLib for uint256; using SentinelListLib for SentinelListLib.SentinelList; /// @dev The timelock period for emergency hook uninstallation. uint256 internal constant _EMERGENCY_TIMELOCK = 1 days; /// @dev The event emitted when an emergency hook uninstallation is initiated. event EmergencyHookUninstallRequest(address hook, uint256 timestamp); /// @dev The event emitted when an emergency hook uninstallation request is reset. event EmergencyHookUninstallRequestReset(address hook, uint256 timestamp); /// @notice Initializes the smart account with the specified entry point. constructor(address anEntryPoint) { require(address(anEntryPoint) != address(0), EntryPointCanNotBeZero()); _ENTRYPOINT = anEntryPoint; _initModuleManager(); } /// @notice Validates a user operation against a specified validator, extracted from the operation's nonce. /// @param op The user operation to validate, encapsulating all transaction details. /// @param userOpHash Hash of the user operation data, used for signature validation. /// @param missingAccountFunds Funds missing from the account's deposit necessary for transaction execution. /// This can be zero if covered by a paymaster or if sufficient deposit exists. /// @return validationData Encoded validation result or failure, propagated from the validator module. /// - Encoded format in validationData: /// - First 20 bytes: Address of the Validator module, to which the validation task is forwarded. /// The validator module returns: /// - `SIG_VALIDATION_SUCCESS` (0) indicates successful validation. /// - `SIG_VALIDATION_FAILED` (1) indicates signature validation failure. /// @dev Expects the validator's address to be encoded in the upper 96 bits of the user operation's nonce. /// This method forwards the validation task to the extracted validator module address. /// @dev The entryPoint calls this function. If validation fails, it returns `VALIDATION_FAILED` (1) otherwise `0`. /// @dev Features Module Enable Mode. /// This Module Enable Mode flow is intended for the module acting as the validator /// for the user operation that triggers the Module Enable Flow. Otherwise, a call to /// `Nexus.installModule` should be included in `userOp.callData`. function validateUserOp( PackedUserOperation calldata op, bytes32 userOpHash, uint256 missingAccountFunds ) external virtual payPrefund(missingAccountFunds) onlyEntryPoint returns (uint256 validationData) { address validator = op.nonce.getValidator(); if (op.nonce.isModuleEnableMode()) { PackedUserOperation memory userOp = op; userOp.signature = _enableMode(userOpHash, op.signature); require(_isValidatorInstalled(validator), ValidatorNotInstalled(validator)); validationData = IValidator(validator).validateUserOp(userOp, userOpHash); } else { require(_isValidatorInstalled(validator), ValidatorNotInstalled(validator)); validationData = IValidator(validator).validateUserOp(op, userOpHash); } } /// @notice Executes transactions in single or batch modes as specified by the execution mode. /// @param mode The execution mode detailing how transactions should be handled (single, batch, default, try/catch). /// @param executionCalldata The encoded transaction data to execute. /// @dev This function handles transaction execution flexibility and is protected by the `onlyEntryPoint` modifier. /// @dev This function also goes through hook checks via withHook modifier. function execute(ExecutionMode mode, bytes calldata executionCalldata) external payable onlyEntryPoint withHook { (CallType callType, ExecType execType) = mode.decodeBasic(); if (callType == CALLTYPE_SINGLE) { _handleSingleExecution(executionCalldata, execType); } else if (callType == CALLTYPE_BATCH) { _handleBatchExecution(executionCalldata, execType); } else if (callType == CALLTYPE_DELEGATECALL) { _handleDelegateCallExecution(executionCalldata, execType); } else { revert UnsupportedCallType(callType); } } /// @notice Executes transactions from an executor module, supporting both single and batch transactions. /// @param mode The execution mode (single or batch, default or try). /// @param executionCalldata The transaction data to execute. /// @return returnData The results of the transaction executions, which may include errors in try mode. /// @dev This function is callable only by an executor module and goes through hook checks. function executeFromExecutor( ExecutionMode mode, bytes calldata executionCalldata ) external payable onlyExecutorModule withHook withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) returns (bytes[] memory returnData) { (CallType callType, ExecType execType) = mode.decodeBasic(); // check if calltype is batch or single or delegate call if (callType == CALLTYPE_SINGLE) { returnData = _handleSingleExecutionAndReturnData(executionCalldata, execType); } else if (callType == CALLTYPE_BATCH) { returnData = _handleBatchExecutionAndReturnData(executionCalldata, execType); } else if (callType == CALLTYPE_DELEGATECALL) { returnData = _handleDelegateCallExecutionAndReturnData(executionCalldata, execType); } else { revert UnsupportedCallType(callType); } } /// @notice Executes a user operation via a call using the contract's context. /// @param userOp The user operation to execute, containing transaction details. /// @param - Hash of the user operation. /// @dev Only callable by the EntryPoint. Decodes the user operation calldata, skipping the first four bytes, and executes the inner call. function executeUserOp(PackedUserOperation calldata userOp, bytes32) external payable virtual onlyEntryPoint withHook { bytes calldata callData = userOp.callData[4:]; (bool success, bytes memory innerCallRet) = address(this).delegatecall(callData); if (success) { emit Executed(userOp, innerCallRet); } else revert ExecutionFailed(); } /// @notice Installs a new module to the smart account. /// @param moduleTypeId The type identifier of the module being installed, which determines its role: /// - 1 for Validator /// - 2 for Executor /// - 3 for Fallback /// - 4 for Hook /// @param module The address of the module to install. /// @param initData Initialization data for the module. /// @dev This function can only be called by the EntryPoint or the account itself for security reasons. /// @dev This function goes through hook checks via withHook modifier through internal function _installModule. function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable onlyEntryPointOrSelf { _installModule(moduleTypeId, module, initData); emit ModuleInstalled(moduleTypeId, module); } /// @notice Uninstalls a module from the smart account. /// @param moduleTypeId The type ID of the module to be uninstalled, matching the installation type: /// - 1 for Validator /// - 2 for Executor /// - 3 for Fallback /// - 4 for Hook /// @param module The address of the module to uninstall. /// @param deInitData De-initialization data for the module. /// @dev Ensures that the operation is authorized and valid before proceeding with the uninstallation. function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable onlyEntryPointOrSelf withHook { require(_isModuleInstalled(moduleTypeId, module, deInitData), ModuleNotInstalled(moduleTypeId, module)); emit ModuleUninstalled(moduleTypeId, module); if (moduleTypeId == MODULE_TYPE_VALIDATOR) { _uninstallValidator(module, deInitData); } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { _uninstallExecutor(module, deInitData); } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { _uninstallFallbackHandler(module, deInitData); } else if (moduleTypeId == MODULE_TYPE_HOOK) { _uninstallHook(module, deInitData); } } function emergencyUninstallHook(address hook, bytes calldata deInitData) external payable onlyEntryPoint { require(_isModuleInstalled(MODULE_TYPE_HOOK, hook, deInitData), ModuleNotInstalled(MODULE_TYPE_HOOK, hook)); AccountStorage storage accountStorage = _getAccountStorage(); uint256 hookTimelock = accountStorage.emergencyUninstallTimelock[hook]; if (hookTimelock == 0) { // if the timelock hasnt been initiated, initiate it accountStorage.emergencyUninstallTimelock[hook] = block.timestamp; emit EmergencyHookUninstallRequest(hook, block.timestamp); } else if (block.timestamp >= hookTimelock + 3 * _EMERGENCY_TIMELOCK) { // if the timelock has been left for too long, reset it accountStorage.emergencyUninstallTimelock[hook] = block.timestamp; emit EmergencyHookUninstallRequestReset(hook, block.timestamp); } else if (block.timestamp >= hookTimelock + _EMERGENCY_TIMELOCK) { // if the timelock expired, clear it and uninstall the hook accountStorage.emergencyUninstallTimelock[hook] = 0; _uninstallHook(hook, deInitData); emit ModuleUninstalled(MODULE_TYPE_HOOK, hook); } else { // if the timelock is initiated but not expired, revert revert EmergencyTimeLockNotExpired(); } } function initializeAccount(bytes calldata initData) external payable virtual { _initModuleManager(); (address bootstrap, bytes memory bootstrapCall) = abi.decode(initData, (address, bytes)); (bool success, ) = bootstrap.delegatecall(bootstrapCall); require(success, NexusInitializationFailed()); require(_hasValidators(), NoValidatorInstalled()); } function setRegistry(IERC7484 newRegistry, address[] calldata attesters, uint8 threshold) external payable onlyEntryPointOrSelf { _configureRegistry(newRegistry, attesters, threshold); } /// @notice Validates a signature according to ERC-1271 standards. /// @param hash The hash of the data being validated. /// @param signature Signature data that needs to be validated. /// @return The status code of the signature validation (`0x1626ba7e` if valid). /// bytes4(keccak256("isValidSignature(bytes32,bytes)") = 0x1626ba7e /// @dev Delegates the validation to a validator module specified within the signature data. function isValidSignature(bytes32 hash, bytes calldata signature) external view virtual override returns (bytes4) { // Handle potential ERC7739 support detection request if (signature.length == 0) { // Forces the compiler to optimize for smaller bytecode size. if (uint256(hash) == (~signature.length / 0xffff) * 0x7739) { return checkERC7739Support(hash, signature); } } // else proceed with normal signature verification // First 20 bytes of data will be validator address and rest of the bytes is complete signature. address validator = address(bytes20(signature[0:20])); require(_isValidatorInstalled(validator), ValidatorNotInstalled(validator)); try IValidator(validator).isValidSignatureWithSender(msg.sender, hash, signature[20:]) returns (bytes4 res) { return res; } catch { return bytes4(0xffffffff); } } /// @notice Retrieves the address of the current implementation from the EIP-1967 slot. /// @notice Checks the 1967 implementation slot, if not found then checks the slot defined by address (Biconomy V2 smart account) /// @return implementation The address of the current contract implementation. function getImplementation() external view returns (address implementation) { assembly { implementation := sload(_ERC1967_IMPLEMENTATION_SLOT) } if (implementation == address(0)) { assembly { implementation := sload(address()) } } } /// @notice Checks if a specific module type is supported by this smart account. /// @param moduleTypeId The identifier of the module type to check. /// @return True if the module type is supported, false otherwise. function supportsModule(uint256 moduleTypeId) external view virtual returns (bool) { if (moduleTypeId == MODULE_TYPE_VALIDATOR) return true; else if (moduleTypeId == MODULE_TYPE_EXECUTOR) return true; else if (moduleTypeId == MODULE_TYPE_FALLBACK) return true; else if (moduleTypeId == MODULE_TYPE_HOOK) return true; else if (moduleTypeId == MODULE_TYPE_MULTI) return true; else return false; } /// @notice Determines if a specific execution mode is supported. /// @param mode The execution mode to evaluate. /// @return isSupported True if the execution mode is supported, false otherwise. function supportsExecutionMode(ExecutionMode mode) external view virtual returns (bool isSupported) { (CallType callType, ExecType execType) = mode.decodeBasic(); // Return true if both the call type and execution type are supported. return (callType == CALLTYPE_SINGLE || callType == CALLTYPE_BATCH || callType == CALLTYPE_DELEGATECALL) && (execType == EXECTYPE_DEFAULT || execType == EXECTYPE_TRY); } /// @notice Determines whether a module is installed on the smart account. /// @param moduleTypeId The ID corresponding to the type of module (Validator, Executor, Fallback, Hook). /// @param module The address of the module to check. /// @param additionalContext Optional context that may be needed for certain checks. /// @return True if the module is installed, false otherwise. function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) external view returns (bool) { return _isModuleInstalled(moduleTypeId, module, additionalContext); } /// @dev EIP712 hashTypedData method. function hashTypedData(bytes32 structHash) external view returns (bytes32) { return _hashTypedData(structHash); } /// @dev EIP712 domain separator. // solhint-disable func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { return _domainSeparator(); } /// Returns the account's implementation ID. /// @return The unique identifier for this account implementation. function accountId() external pure virtual returns (string memory) { return _ACCOUNT_IMPLEMENTATION_ID; } /// Upgrades the contract to a new implementation and calls a function on the new contract. /// @notice Updates two slots 1. ERC1967 slot and /// 2. address() slot in case if it's potentially upgraded earlier from Biconomy V2 account, /// as Biconomy v2 Account (proxy) reads implementation from the slot that is defined by its address /// @param newImplementation The address of the new contract implementation. /// @param data The calldata to be sent to the new implementation. function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual override withHook { require(newImplementation != address(0), InvalidImplementationAddress()); bool res; assembly { res := gt(extcodesize(newImplementation), 0) } require(res, InvalidImplementationAddress()); // update the address() storage slot as well. assembly { sstore(address(), newImplementation) } UUPSUpgradeable.upgradeToAndCall(newImplementation, data); } /// @dev For automatic detection that the smart account supports the ERC7739 workflow /// Iterates over all the validators but only if this is a detection request /// ERC-7739 spec assumes that if the account doesn't support ERC-7739 /// it will try to handle the detection request as it was normal sig verification /// request and will return 0xffffffff since it won't be able to verify the 0x signature /// against 0x7739...7739 hash. /// So this approach is consistent with the ERC-7739 spec. /// If no validator supports ERC-7739, this function returns false /// thus the account will proceed with normal signature verification /// and return 0xffffffff as a result. function checkERC7739Support(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) { bytes4 result; unchecked { SentinelListLib.SentinelList storage validators = _getAccountStorage().validators; address next = validators.entries[SENTINEL]; while (next != ZERO_ADDRESS && next != SENTINEL) { bytes4 support = IValidator(next).isValidSignatureWithSender(msg.sender, hash, signature); if (bytes2(support) == bytes2(SUPPORTS_ERC7739) && support > result) { result = support; } next = validators.getNext(next); } } return result == bytes4(0) ? bytes4(0xffffffff) : result; } /// @dev Ensures that only authorized callers can upgrade the smart contract implementation. /// This is part of the UUPS (Universal Upgradeable Proxy Standard) pattern. /// @param newImplementation The address of the new implementation to upgrade to. function _authorizeUpgrade(address newImplementation) internal virtual override(UUPSUpgradeable) onlyEntryPointOrSelf {} /// @dev EIP712 domain name and version. function _domainNameAndVersion() internal pure override returns (string memory name, string memory version) { name = "Nexus"; version = "1.0.1"; } }
// 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) } } _; } }
// 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: MIT pragma solidity ^0.8.27; import { Execution } from "../types/DataTypes.sol"; /// @title ExecutionLib /// @author zeroknots.eth | rhinestone.wtf /// Helper Library for decoding Execution calldata /// malloc for memory allocation is bad for gas. use this assembly instead library ExecLib { error InvalidBatchCallData(); function get2771CallData(bytes calldata cd) internal view returns (bytes memory callData) { /// @solidity memory-safe-assembly (cd); assembly { // as per solidity docs function allocate(length) -> pos { pos := mload(0x40) mstore(0x40, add(pos, length)) } callData := allocate(add(calldatasize(), 0x20)) //allocate extra 0x20 to store length mstore(callData, add(calldatasize(), 0x14)) //store length, extra 0x14 is for msg.sender address calldatacopy(add(callData, 0x20), 0, calldatasize()) // The msg.sender address is shifted to the left by 12 bytes to remove the padding // Then the address without padding is stored right after the calldata let senderPtr := allocate(0x14) mstore(senderPtr, shl(96, caller())) } } function decodeBatch(bytes calldata callData) internal view returns (Execution[] calldata executionBatch) { /* * Batch Call Calldata Layout * Offset (in bytes) | Length (in bytes) | Contents * 0x0 | 0x4 | bytes4 function selector * 0x4 | - | abi.encode(IERC7579Execution.Execution[]) */ assembly ("memory-safe") { let dataPointer := add(callData.offset, calldataload(callData.offset)) // Extract the ERC7579 Executions executionBatch.offset := add(dataPointer, 32) executionBatch.length := calldataload(dataPointer) } } function encodeBatch(Execution[] memory executions) internal pure returns (bytes memory callData) { callData = abi.encode(executions); } function decodeSingle(bytes calldata executionCalldata) internal pure returns (address target, uint256 value, bytes calldata callData) { target = address(bytes20(executionCalldata[0:20])); value = uint256(bytes32(executionCalldata[20:52])); callData = executionCalldata[52:]; } function decodeDelegateCall(bytes calldata executionCalldata) internal pure returns (address delegate, bytes calldata callData) { // destructure executionCallData according to single exec delegate = address(uint160(bytes20(executionCalldata[0:20]))); callData = executionCalldata[20:]; } function encodeSingle(address target, uint256 value, bytes memory callData) internal pure returns (bytes memory userOpCalldata) { userOpCalldata = abi.encodePacked(target, value, callData); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IERC4337Account } from "./IERC4337Account.sol"; import { IERC7579Account } from "./IERC7579Account.sol"; import { INexusEventsAndErrors } from "./INexusEventsAndErrors.sol"; /// @title Nexus - INexus Interface /// @notice Integrates ERC-4337 and ERC-7579 standards to manage smart accounts within the Nexus suite. /// @dev Consolidates ERC-4337 user operations and ERC-7579 configurations into a unified interface for smart account management. /// It extends both IERC4337Account and IERC7579Account, enhancing modular capabilities and supporting advanced contract architectures. /// Includes error definitions for robust handling of common issues such as unsupported module types and execution failures. /// The initialize function sets up the account with validators and configurations, ensuring readiness for use. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface INexus is IERC4337Account, IERC7579Account, INexusEventsAndErrors { /// @notice Initializes the smart account with a validator and custom data. /// @dev This method sets up the account for operation, linking it with a validator and initializing it with specific data. /// Can be called directly or via a factory. /// @param initData Encoded data used for the account's configuration during initialization. function initializeAccount(bytes calldata initData) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IEntryPoint } from "account-abstraction/interfaces/IEntryPoint.sol"; import { IBaseAccount } from "../interfaces/base/IBaseAccount.sol"; /// @title Nexus - BaseAccount /// @notice Implements ERC-4337 and ERC-7579 standards for account management and access control within the Nexus suite. /// @dev Manages entry points and configurations as specified in the ERC-4337 and ERC-7579 documentation. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady contract BaseAccount is IBaseAccount { /// @notice Identifier for this implementation on the network string internal constant _ACCOUNT_IMPLEMENTATION_ID = "biconomy.nexus.1.0.0"; /// @notice The canonical address for the ERC4337 EntryPoint contract, version 0.7. /// This address is consistent across all supported networks. address internal immutable _ENTRYPOINT; /// @dev Ensures the caller is either the EntryPoint or this account itself. /// Reverts with AccountAccessUnauthorized if the check fails. modifier onlyEntryPointOrSelf() { require(msg.sender == _ENTRYPOINT || msg.sender == address(this), AccountAccessUnauthorized()); _; } /// @dev Ensures the caller is the EntryPoint. /// Reverts with AccountAccessUnauthorized if the check fails. modifier onlyEntryPoint() { require(msg.sender == _ENTRYPOINT, AccountAccessUnauthorized()); _; } /// @dev Sends to the EntryPoint (i.e. `msg.sender`) the missing funds for this transaction. /// Subclass MAY override this modifier for better funds management. /// (e.g. send to the EntryPoint more than the minimum required, so that in future transactions /// it will not be required to send again) /// /// `missingAccountFunds` is the minimum value this modifier should send the EntryPoint, /// which MAY be zero, in case there is enough deposit, or the userOp has a paymaster. modifier payPrefund(uint256 missingAccountFunds) virtual { _; /// @solidity memory-safe-assembly assembly { 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 Adds deposit to the EntryPoint to fund transactions. function addDeposit() external payable virtual { address entryPointAddress = _ENTRYPOINT; /// @solidity memory-safe-assembly assembly { // The EntryPoint has balance accounting logic in the `receive()` function. if iszero(call(gas(), entryPointAddress, callvalue(), codesize(), 0x00, codesize(), 0x00)) { revert(codesize(), 0x00) } // For gas estimation. } } /// @notice Withdraws ETH from the EntryPoint to a specified address. /// @param to The address to receive the withdrawn funds. /// @param amount The amount to withdraw. function withdrawDepositTo(address to, uint256 amount) external payable virtual onlyEntryPointOrSelf { address entryPointAddress = _ENTRYPOINT; assembly { let freeMemPtr := mload(0x40) // Store the free memory pointer. mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x205c2878000000000000000000000000) // `withdrawTo(address,uint256)`. if iszero(call(gas(), entryPointAddress, 0, 0x10, 0x44, codesize(), 0x00)) { returndatacopy(freeMemPtr, 0x00, returndatasize()) revert(freeMemPtr, returndatasize()) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @notice Gets the nonce for a particular key. /// @param key The nonce key. /// @return The nonce associated with the key. function nonce(uint192 key) external view virtual returns (uint256) { return IEntryPoint(_ENTRYPOINT).getNonce(address(this), key); } /// @notice Returns the current deposit balance of this account on the EntryPoint. /// @return result The current balance held at the EntryPoint. function getDeposit() external view virtual returns (uint256 result) { address entryPointAddress = _ENTRYPOINT; /// @solidity memory-safe-assembly assembly { mstore(0x20, address()) // Store the `account` argument. mstore(0x00, 0x70a08231) // `balanceOf(address)`. result := mul( // Returns 0 if the EntryPoint does not exist. mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), entryPointAddress, 0x1c, 0x24, 0x20, 0x20) ) ) } } /// @notice Retrieves the address of the EntryPoint contract, currently using version 0.7. /// @dev This function returns the address of the canonical ERC4337 EntryPoint contract. /// It can be overridden to return a different EntryPoint address if needed. /// @return The address of the EntryPoint contract. function entryPoint() external view returns (address) { return _ENTRYPOINT; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; interface IERC7484 { event NewTrustedAttesters(); /** * Allows Smart Accounts - the end users of the registry - to appoint * one or many attesters as trusted. * @dev this function reverts, if address(0), or duplicates are provided in attesters[] * * @param threshold The minimum number of attestations required for a module * to be considered secure. * @param attesters The addresses of the attesters to be trusted. */ function trustAttesters(uint8 threshold, address[] calldata attesters) external; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* Check with Registry internal attesters */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function check(address module) external view; function checkForAccount(address smartAccount, address module) external view; function check(address module, uint256 moduleType) external view; function checkForAccount(address smartAccount, address module, uint256 moduleType) external view; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* Check with external attester(s) */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function check(address module, address[] calldata attesters, uint256 threshold) external view; function check(address module, uint256 moduleType, address[] calldata attesters, uint256 threshold) external view; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { SentinelListLib } from "sentinellist/SentinelList.sol"; import { Storage } from "./Storage.sol"; import { IHook } from "../interfaces/modules/IHook.sol"; import { IModule } from "../interfaces/modules/IModule.sol"; import { IExecutor } from "../interfaces/modules/IExecutor.sol"; import { IFallback } from "../interfaces/modules/IFallback.sol"; import { IValidator } from "../interfaces/modules/IValidator.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_STATIC } from "../lib/ModeLib.sol"; import { ExecLib } from "../lib/ExecLib.sol"; import { LocalCallDataParserLib } from "../lib/local/LocalCallDataParserLib.sol"; import { IModuleManagerEventsAndErrors } from "../interfaces/base/IModuleManagerEventsAndErrors.sol"; import { MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK, MODULE_TYPE_HOOK, MODULE_TYPE_MULTI, MODULE_ENABLE_MODE_TYPE_HASH, ERC1271_MAGICVALUE } from "../types/Constants.sol"; import { EIP712 } from "solady/utils/EIP712.sol"; import { ExcessivelySafeCall } from "excessively-safe-call/ExcessivelySafeCall.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; /// @title Nexus - ModuleManager /// @notice Manages Validator, Executor, Hook, and Fallback modules within the Nexus suite, supporting /// @dev Implements SentinelList for managing modules via a linked list structure, adhering to ERC-7579. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady abstract contract ModuleManager is Storage, EIP712, IModuleManagerEventsAndErrors, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; using LocalCallDataParserLib for bytes; using ExecLib for address; using ExcessivelySafeCall for address; /// @notice Ensures the message sender is a registered executor module. modifier onlyExecutorModule() virtual { require(_getAccountStorage().executors.contains(msg.sender), InvalidModule(msg.sender)); _; } /// @notice Does pre-checks and post-checks using an installed hook on the account. /// @dev sender, msg.data and msg.value is passed to the hook to implement custom flows. modifier withHook() { address hook = _getHook(); if (hook == address(0)) { _; } else { bytes memory hookData = IHook(hook).preCheck(msg.sender, msg.value, msg.data); _; IHook(hook).postCheck(hookData); } } receive() external payable {} /// @dev Fallback function to manage incoming calls using designated handlers based on the call type. fallback(bytes calldata callData) external payable withHook returns (bytes memory) { return _fallback(callData); } /// @dev Retrieves a paginated list of validator addresses from the linked list. /// This utility function is not defined by the ERC-7579 standard and is implemented to facilitate /// easier management and retrieval of large sets of validator modules. /// @param cursor The address to start pagination from, or zero to start from the first entry. /// @param size The number of validator addresses to return. /// @return array An array of validator addresses. /// @return next The address to use as a cursor for the next page of results. function getValidatorsPaginated(address cursor, uint256 size) external view returns (address[] memory array, address next) { (array, next) = _paginate(_getAccountStorage().validators, cursor, size); } /// @dev Retrieves a paginated list of executor addresses from the linked list. /// This utility function is not defined by the ERC-7579 standard and is implemented to facilitate /// easier management and retrieval of large sets of executor modules. /// @param cursor The address to start pagination from, or zero to start from the first entry. /// @param size The number of executor addresses to return. /// @return array An array of executor addresses. /// @return next The address to use as a cursor for the next page of results. function getExecutorsPaginated(address cursor, uint256 size) external view returns (address[] memory array, address next) { (array, next) = _paginate(_getAccountStorage().executors, cursor, size); } /// @notice Retrieves the currently active hook address. /// @return hook The address of the active hook module. function getActiveHook() external view returns (address hook) { return _getHook(); } /// @notice Fetches the fallback handler for a specific selector. /// @param selector The function selector to query. /// @return calltype The type of call that the handler manages. /// @return handler The address of the fallback handler. function getFallbackHandlerBySelector(bytes4 selector) external view returns (CallType, address) { FallbackHandler memory handler = _getAccountStorage().fallbacks[selector]; return (handler.calltype, handler.handler); } /// @dev Initializes the module manager by setting up default states for validators and executors. function _initModuleManager() internal virtual { // account module storage AccountStorage storage ams = _getAccountStorage(); ams.executors.init(); ams.validators.init(); } /// @dev Implements Module Enable Mode flow. /// @param packedData Data source to parse data required to perform Module Enable mode from. /// @return userOpSignature the clean signature which can be further used for userOp validation function _enableMode(bytes32 userOpHash, bytes calldata packedData) internal returns (bytes calldata userOpSignature) { address module; uint256 moduleType; bytes calldata moduleInitData; bytes calldata enableModeSignature; (module, moduleType, moduleInitData, enableModeSignature, userOpSignature) = packedData.parseEnableModeData(); if (!_checkEnableModeSignature(_getEnableModeDataHash(module, moduleType, userOpHash, moduleInitData), enableModeSignature)) revert EnableModeSigError(); _installModule(moduleType, module, moduleInitData); } /// @notice Installs a new module to the smart account. /// @param moduleTypeId The type identifier of the module being installed, which determines its role: /// - 0 for MultiType /// - 1 for Validator /// - 2 for Executor /// - 3 for Fallback /// - 4 for Hook /// @param module The address of the module to install. /// @param initData Initialization data for the module. /// @dev This function goes through hook checks via withHook modifier. /// @dev No need to check that the module is already installed, as this check is done /// when trying to sstore the module in an appropriate SentinelList function _installModule(uint256 moduleTypeId, address module, bytes calldata initData) internal withHook { if (module == address(0)) revert ModuleAddressCanNotBeZero(); if (moduleTypeId == MODULE_TYPE_VALIDATOR) { _installValidator(module, initData); } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { _installExecutor(module, initData); } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { _installFallbackHandler(module, initData); } else if (moduleTypeId == MODULE_TYPE_HOOK) { _installHook(module, initData); } else if (moduleTypeId == MODULE_TYPE_MULTI) { _multiTypeInstall(module, initData); } else { revert InvalidModuleTypeId(moduleTypeId); } } /// @dev Installs a new validator module after checking if it matches the required module type. /// @param validator The address of the validator module to be installed. /// @param data Initialization data to configure the validator upon installation. function _installValidator(address validator, bytes calldata data) internal virtual withRegistry(validator, MODULE_TYPE_VALIDATOR) { if (!IValidator(validator).isModuleType(MODULE_TYPE_VALIDATOR)) revert MismatchModuleTypeId(MODULE_TYPE_VALIDATOR); _getAccountStorage().validators.push(validator); IValidator(validator).onInstall(data); } /// @dev Uninstalls a validator module /!\ ensuring the account retains at least one validator. /// @param validator The address of the validator to be uninstalled. /// @param data De-initialization data to configure the validator upon uninstallation. function _uninstallValidator(address validator, bytes calldata data) internal virtual { SentinelListLib.SentinelList storage validators = _getAccountStorage().validators; (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); // Perform the removal first validators.pop(prev, validator); // Sentinel pointing to itself / zero means the list is empty / uninitialized, so check this after removal // Below error is very specific to uninstalling validators. require(_hasValidators(), CanNotRemoveLastValidator()); validator.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, disableModuleData)); } /// @dev Installs a new executor module after checking if it matches the required module type. /// @param executor The address of the executor module to be installed. /// @param data Initialization data to configure the executor upon installation. function _installExecutor(address executor, bytes calldata data) internal virtual withRegistry(executor, MODULE_TYPE_EXECUTOR) { if (!IExecutor(executor).isModuleType(MODULE_TYPE_EXECUTOR)) revert MismatchModuleTypeId(MODULE_TYPE_EXECUTOR); _getAccountStorage().executors.push(executor); IExecutor(executor).onInstall(data); } /// @dev Uninstalls an executor module by removing it from the executors list. /// @param executor The address of the executor to be uninstalled. /// @param data De-initialization data to configure the executor upon uninstallation. function _uninstallExecutor(address executor, bytes calldata data) internal virtual { (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); _getAccountStorage().executors.pop(prev, executor); executor.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, disableModuleData)); } /// @dev Installs a hook module, ensuring no other hooks are installed before proceeding. /// @param hook The address of the hook to be installed. /// @param data Initialization data to configure the hook upon installation. function _installHook(address hook, bytes calldata data) internal virtual withRegistry(hook, MODULE_TYPE_HOOK) { if (!IHook(hook).isModuleType(MODULE_TYPE_HOOK)) revert MismatchModuleTypeId(MODULE_TYPE_HOOK); address currentHook = _getHook(); require(currentHook == address(0), HookAlreadyInstalled(currentHook)); _setHook(hook); IHook(hook).onInstall(data); } /// @dev Uninstalls a hook module, ensuring the current hook matches the one intended for uninstallation. /// @param hook The address of the hook to be uninstalled. /// @param data De-initialization data to configure the hook upon uninstallation. function _uninstallHook(address hook, bytes calldata data) internal virtual { _setHook(address(0)); hook.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, data)); } /// @dev Sets the current hook in the storage to the specified address. /// @param hook The new hook address. function _setHook(address hook) internal virtual { _getAccountStorage().hook = IHook(hook); } /// @dev Installs a fallback handler for a given selector with initialization data. /// @param handler The address of the fallback handler to install. /// @param params The initialization parameters including the selector and call type. function _installFallbackHandler(address handler, bytes calldata params) internal virtual withRegistry(handler, MODULE_TYPE_FALLBACK) { if (!IFallback(handler).isModuleType(MODULE_TYPE_FALLBACK)) revert MismatchModuleTypeId(MODULE_TYPE_FALLBACK); // Extract the function selector from the provided parameters. bytes4 selector = bytes4(params[0:4]); // Extract the call type from the provided parameters. CallType calltype = CallType.wrap(bytes1(params[4])); require(calltype == CALLTYPE_SINGLE || calltype == CALLTYPE_STATIC, FallbackCallTypeInvalid()); // Extract the initialization data from the provided parameters. bytes memory initData = params[5:]; // Revert if the selector is either `onInstall(bytes)` (0x6d61fe70) or `onUninstall(bytes)` (0x8a91b0e3) or explicit bytes(0). // These selectors are explicitly forbidden to prevent security vulnerabilities. // Allowing these selectors would enable unauthorized users to uninstall and reinstall critical modules. // If a validator module is uninstalled and reinstalled without proper authorization, it can compromise // the account's security and integrity. By restricting these selectors, we ensure that the fallback handler // cannot be manipulated to disrupt the expected behavior and security of the account. require(!(selector == bytes4(0x6d61fe70) || selector == bytes4(0x8a91b0e3) || selector == bytes4(0)), FallbackSelectorForbidden()); // Revert if a fallback handler is already installed for the given selector. // This check ensures that we do not overwrite an existing fallback handler, which could lead to unexpected behavior. require(!_isFallbackHandlerInstalled(selector), FallbackAlreadyInstalledForSelector(selector)); // Store the fallback handler and its call type in the account storage. // This maps the function selector to the specified fallback handler and call type. _getAccountStorage().fallbacks[selector] = FallbackHandler(handler, calltype); // Invoke the `onInstall` function of the fallback handler with the provided initialization data. // This step allows the fallback handler to perform any necessary setup or initialization. IFallback(handler).onInstall(initData); } /// @dev Uninstalls a fallback handler for a given selector. /// @param fallbackHandler The address of the fallback handler to uninstall. /// @param data The de-initialization data containing the selector. function _uninstallFallbackHandler(address fallbackHandler, bytes calldata data) internal virtual { _getAccountStorage().fallbacks[bytes4(data[0:4])] = FallbackHandler(address(0), CallType.wrap(0x00)); fallbackHandler.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, data[4:])); } /// @notice Installs a module with multiple types in a single operation. /// @dev This function handles installing a multi-type module by iterating through each type and initializing it. /// The initData should include an ABI-encoded tuple of (uint[] types, bytes[] initDatas). /// @param module The address of the multi-type module. /// @param initData Initialization data for each type within the module. function _multiTypeInstall(address module, bytes calldata initData) internal virtual { (uint256[] calldata types, bytes[] calldata initDatas) = initData.parseMultiTypeInitData(); uint256 length = types.length; if (initDatas.length != length) revert InvalidInput(); // iterate over all module types and install the module as a type accordingly for (uint256 i; i < length; i++) { uint256 theType = types[i]; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSTALL VALIDATORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ if (theType == MODULE_TYPE_VALIDATOR) { _installValidator(module, initDatas[i]); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSTALL EXECUTORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (theType == MODULE_TYPE_EXECUTOR) { _installExecutor(module, initDatas[i]); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSTALL FALLBACK */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (theType == MODULE_TYPE_FALLBACK) { _installFallbackHandler(module, initDatas[i]); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSTALL HOOK (global only, not sig-specific) */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (theType == MODULE_TYPE_HOOK) { _installHook(module, initDatas[i]); } } } /// @notice Checks if an enable mode signature is valid. /// @param structHash data hash. /// @param sig Signature. function _checkEnableModeSignature(bytes32 structHash, bytes calldata sig) internal view returns (bool) { address enableModeSigValidator = address(bytes20(sig[0:20])); if (!_isValidatorInstalled(enableModeSigValidator)) { revert ValidatorNotInstalled(enableModeSigValidator); } bytes32 eip712Digest = _hashTypedData(structHash); // Use standard IERC-1271/ERC-7739 interface. // Even if the validator doesn't support 7739 under the hood, it is still secure, // as eip712digest is already built based on 712Domain of this Smart Account // This interface should always be exposed by validators as per ERC-7579 try IValidator(enableModeSigValidator).isValidSignatureWithSender(address(this), eip712Digest, sig[20:]) returns (bytes4 res) { return res == ERC1271_MAGICVALUE; } catch { return false; } } /// @notice Builds the enable mode data hash as per eip712 /// @param module Module being enabled /// @param moduleType Type of the module as per EIP-7579 /// @param userOpHash Hash of the User Operation /// @param initData Module init data. /// @return structHash data hash function _getEnableModeDataHash(address module, uint256 moduleType, bytes32 userOpHash, bytes calldata initData) internal view returns (bytes32) { return keccak256(abi.encode(MODULE_ENABLE_MODE_TYPE_HASH, module, moduleType, userOpHash, keccak256(initData))); } /// @notice Checks if a module is installed on the smart account. /// @param moduleTypeId The module type ID. /// @param module The module address. /// @param additionalContext Additional context for checking installation. /// @return True if the module is installed, false otherwise. function _isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) internal view returns (bool) { additionalContext; if (moduleTypeId == MODULE_TYPE_VALIDATOR) { return _isValidatorInstalled(module); } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { return _isExecutorInstalled(module); } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { bytes4 selector; if (additionalContext.length >= 4) { selector = bytes4(additionalContext[0:4]); } else { selector = bytes4(0x00000000); } return _isFallbackHandlerInstalled(selector, module); } else if (moduleTypeId == MODULE_TYPE_HOOK) { return _isHookInstalled(module); } else { return false; } } /// @dev Checks if a fallback handler is set for a given selector. /// @param selector The function selector to check. /// @return True if a fallback handler is set, otherwise false. function _isFallbackHandlerInstalled(bytes4 selector) internal view virtual returns (bool) { FallbackHandler storage handler = _getAccountStorage().fallbacks[selector]; return handler.handler != address(0); } /// @dev Checks if the expected fallback handler is installed for a given selector. /// @param selector The function selector to check. /// @param expectedHandler The address of the handler expected to be installed. /// @return True if the installed handler matches the expected handler, otherwise false. function _isFallbackHandlerInstalled(bytes4 selector, address expectedHandler) internal view returns (bool) { FallbackHandler storage handler = _getAccountStorage().fallbacks[selector]; return handler.handler == expectedHandler; } /// @dev Checks if a validator is currently installed. /// @param validator The address of the validator to check. /// @return True if the validator is installed, otherwise false. function _isValidatorInstalled(address validator) internal view virtual returns (bool) { return _getAccountStorage().validators.contains(validator); } /// @dev Checks if there is at least one validator installed. /// @return True if there is at least one validator, otherwise false. function _hasValidators() internal view returns (bool) { return _getAccountStorage().validators.getNext(address(0x01)) != address(0x01) && _getAccountStorage().validators.getNext(address(0x01)) != address(0x00); } /// @dev Checks if an executor is currently installed. /// @param executor The address of the executor to check. /// @return True if the executor is installed, otherwise false. function _isExecutorInstalled(address executor) internal view virtual returns (bool) { return _getAccountStorage().executors.contains(executor); } /// @dev Checks if a hook is currently installed. /// @param hook The address of the hook to check. /// @return True if the hook is installed, otherwise false. function _isHookInstalled(address hook) internal view returns (bool) { return _getHook() == hook; } /// @dev Retrieves the current hook from the storage. /// @return hook The address of the current hook. function _getHook() internal view returns (address hook) { hook = address(_getAccountStorage().hook); } function _fallback(bytes calldata callData) private returns (bytes memory result) { bool success; FallbackHandler storage $fallbackHandler = _getAccountStorage().fallbacks[msg.sig]; address handler = $fallbackHandler.handler; CallType calltype = $fallbackHandler.calltype; if (handler != address(0)) { //if there's a fallback handler, call it if (calltype == CALLTYPE_STATIC) { (success, result) = handler.staticcall(ExecLib.get2771CallData(callData)); } else if (calltype == CALLTYPE_SINGLE) { (success, result) = handler.call{ value: msg.value }(ExecLib.get2771CallData(callData)); } else { revert UnsupportedCallType(calltype); } // Use revert message from fallback handler if the call was not successful if (!success) { assembly { revert(add(result, 0x20), mload(result)) } } } else { // If there's no handler, the call can be one of onERCXXXReceived() bytes32 s; /// @solidity memory-safe-assembly assembly { s := shr(224, calldataload(0)) // 0x150b7a02: `onERC721Received(address,address,uint256,bytes)`. // 0xf23a6e61: `onERC1155Received(address,address,uint256,uint256,bytes)`. // 0xbc197c81: `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. if or(eq(s, 0x150b7a02), or(eq(s, 0xf23a6e61), eq(s, 0xbc197c81))) { success := true // it is one of onERCXXXReceived result := mload(0x40) //result was set to 0x60 as it was empty, so we need to find a new space for it mstore(result, 0x04) //store length mstore(add(result, 0x20), shl(224, s)) //store calldata mstore(0x40, add(result, 0x24)) //allocate memory } } // if there was no handler and it is not the onERCXXXReceived call, revert require(success, MissingFallbackHandler(msg.sig)); } } /// @dev Helper function to paginate entries in a SentinelList. /// @param list The SentinelList to paginate. /// @param cursor The cursor to start paginating from. /// @param size The number of entries to return. /// @return array The array of addresses in the list. /// @return nextCursor The cursor for the next page of entries. function _paginate( SentinelListLib.SentinelList storage list, address cursor, uint256 size ) private view returns (address[] memory array, address nextCursor) { (array, nextCursor) = list.getEntriesPaginated(cursor, size); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { Execution } from "../types/DataTypes.sol"; import { IExecutionHelperEventsAndErrors } from "../interfaces/base/IExecutionHelper.sol"; import { ExecType, EXECTYPE_DEFAULT, EXECTYPE_TRY } from "../lib/ModeLib.sol"; import { ExecLib } from "../lib/ExecLib.sol"; /// @title Nexus - ExecutionHelper /// @notice Implements execution management within the Nexus suite, facilitating transaction execution strategies and /// error handling. /// @dev Provides mechanisms for direct and batched transactions with both committed and tentative execution strategies /// as per ERC-4337 and ERC-7579 standards. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady contract ExecutionHelper is IExecutionHelperEventsAndErrors { using ExecLib for bytes; /// @notice Executes a call to a target address with specified value and data. /// @notice calls to an EOA should be counted as successful. /// @param target The address to execute the call on. /// @param value The amount of wei to send with the call. /// @param callData The calldata to send. /// @return result The bytes returned from the execution, which contains the returned data from the target address. function _execute(address target, uint256 value, bytes calldata callData) internal virtual returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) calldatacopy(result, callData.offset, callData.length) if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } mstore(result, returndatasize()) // Store the length. let o := add(result, 0x20) returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. mstore(0x40, add(o, returndatasize())) // Allocate the memory. } } /// @notice Executes a call to a target address with specified value and data. /// Same as _execute but without return data for gas optimization. function _executeNoReturndata(address target, uint256 value, bytes calldata callData) internal virtual { /// @solidity memory-safe-assembly assembly { let result := mload(0x40) calldatacopy(result, callData.offset, callData.length) if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } mstore(0x40, add(result, callData.length)) //allocate memory } } /// @notice Tries to execute a call and captures if it was successful or not. /// @dev Similar to _execute but returns a success boolean and catches reverts instead of propagating them. /// @notice calls to an EOA should be counted as successful. /// @param target The address to execute the call on. /// @param value The amount of wei to send with the call. /// @param callData The calldata to send. /// @return success True if the execution was successful, false otherwise. /// @return result The bytes returned from the execution, which contains the returned data from the target address. function _tryExecute(address target, uint256 value, bytes calldata callData) internal virtual returns (bool success, bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) calldatacopy(result, callData.offset, callData.length) success := call(gas(), target, value, result, callData.length, codesize(), 0x00) mstore(result, returndatasize()) // Store the length. let o := add(result, 0x20) returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. mstore(0x40, add(o, returndatasize())) // Allocate the memory. } } /// @notice Executes a batch of calls. /// @param executions An array of Execution structs each containing target, value, and calldata. /// @return result An array of bytes returned from each executed call, corresponding to the returndata from each target address. function _executeBatch(Execution[] calldata executions) internal returns (bytes[] memory result) { result = new bytes[](executions.length); Execution calldata exec; for (uint256 i; i < executions.length; i++) { exec = executions[i]; result[i] = _execute(exec.target, exec.value, exec.callData); } } /// @notice Executes a batch of calls without returning the result. /// @param executions An array of Execution structs each containing target, value, and calldata. function _executeBatchNoReturndata(Execution[] calldata executions) internal { Execution calldata exec; for (uint256 i; i < executions.length; i++) { exec = executions[i]; _executeNoReturndata(exec.target, exec.value, exec.callData); } } /// @notice Tries to execute a batch of calls and emits an event for each unsuccessful call. /// @param executions An array of Execution structs. /// @return result An array of bytes returned from each executed call, with unsuccessful calls marked by events. function _tryExecuteBatch(Execution[] calldata executions) internal returns (bytes[] memory result) { result = new bytes[](executions.length); Execution calldata exec; for (uint256 i; i < executions.length; i++) { exec = executions[i]; bool success; (success, result[i]) = _tryExecute(exec.target, exec.value, exec.callData); if (!success) emit TryExecuteUnsuccessful(exec.callData, result[i]); } } /// @dev Execute a delegatecall with `delegate` on this account. /// @return result The bytes returned from the delegatecall, which contains the returned data from the delegate contract. function _executeDelegatecall(address delegate, bytes calldata callData) internal returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) calldatacopy(result, callData.offset, callData.length) // Forwards the `data` to `delegate` via delegatecall. if iszero(delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } mstore(result, returndatasize()) // Store the length. let o := add(result, 0x20) returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. mstore(0x40, add(o, returndatasize())) // Allocate the memory. } } /// @dev Execute a delegatecall with `delegate` on this account. /// Same as _executeDelegatecall but without return data for gas optimization. function _executeDelegatecallNoReturndata(address delegate, bytes calldata callData) internal { /// @solidity memory-safe-assembly assembly { let result := mload(0x40) calldatacopy(result, callData.offset, callData.length) if iszero(delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } mstore(0x40, add(result, callData.length)) //allocate memory } } /// @dev Execute a delegatecall with `delegate` on this account and catch reverts. /// @return success True if the delegatecall was successful, false otherwise. /// @return result The bytes returned from the delegatecall, which contains the returned data from the delegate contract. function _tryExecuteDelegatecall(address delegate, bytes calldata callData) internal returns (bool success, bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) calldatacopy(result, callData.offset, callData.length) // Forwards the `data` to `delegate` via delegatecall. success := delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00) mstore(result, returndatasize()) // Store the length. let o := add(result, 0x20) returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. mstore(0x40, add(o, returndatasize())) // Allocate the memory. } } /// @dev Executes a single transaction based on the specified execution type. /// @param executionCalldata The calldata containing the transaction details (target address, value, and data). /// @param execType The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). function _handleSingleExecution(bytes calldata executionCalldata, ExecType execType) internal { (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); if (execType == EXECTYPE_DEFAULT) _executeNoReturndata(target, value, callData); else if (execType == EXECTYPE_TRY) { (bool success, bytes memory result) = _tryExecute(target, value, callData); if (!success) emit TryExecuteUnsuccessful(callData, result); } else revert UnsupportedExecType(execType); } /// @dev Executes a batch of transactions based on the specified execution type. /// @param executionCalldata The calldata for a batch of transactions. /// @param execType The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). function _handleBatchExecution(bytes calldata executionCalldata, ExecType execType) internal { Execution[] calldata executions = executionCalldata.decodeBatch(); if (execType == EXECTYPE_DEFAULT) _executeBatchNoReturndata(executions); else if (execType == EXECTYPE_TRY) _tryExecuteBatch(executions); else revert UnsupportedExecType(execType); } /// @dev Executes a single transaction based on the specified execution type. /// @param executionCalldata The calldata containing the transaction details (target address, value, and data). /// @param execType The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). function _handleDelegateCallExecution(bytes calldata executionCalldata, ExecType execType) internal { (address delegate, bytes calldata callData) = executionCalldata.decodeDelegateCall(); if (execType == EXECTYPE_DEFAULT) _executeDelegatecallNoReturndata(delegate, callData); else if (execType == EXECTYPE_TRY) { (bool success, bytes memory result) = _tryExecuteDelegatecall(delegate, callData); if (!success) emit TryDelegateCallUnsuccessful(callData, result); } else revert UnsupportedExecType(execType); } /// @dev Executes a single transaction based on the specified execution type. /// @param executionCalldata The calldata containing the transaction details (target address, value, and data). /// @param execType The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). /// @return returnData An array containing the execution result. In the case of a single transaction, the array contains one element. function _handleSingleExecutionAndReturnData(bytes calldata executionCalldata, ExecType execType) internal returns (bytes[] memory returnData) { (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); returnData = new bytes[](1); bool success; // check if execType is revert(default) or try if (execType == EXECTYPE_DEFAULT) { returnData[0] = _execute(target, value, callData); } else if (execType == EXECTYPE_TRY) { (success, returnData[0]) = _tryExecute(target, value, callData); if (!success) emit TryExecuteUnsuccessful(callData, returnData[0]); } else { revert UnsupportedExecType(execType); } } /// @dev Executes a batch of transactions based on the specified execution type. /// @param executionCalldata The calldata for a batch of transactions. /// @param execType The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). /// @return returnData An array containing the execution results for each transaction in the batch. function _handleBatchExecutionAndReturnData(bytes calldata executionCalldata, ExecType execType) internal returns (bytes[] memory returnData) { Execution[] calldata executions = executionCalldata.decodeBatch(); if (execType == EXECTYPE_DEFAULT) returnData = _executeBatch(executions); else if (execType == EXECTYPE_TRY) returnData = _tryExecuteBatch(executions); else revert UnsupportedExecType(execType); } /// @dev Executes a single transaction based on the specified execution type. /// @param executionCalldata The calldata containing the transaction details (target address, value, and data). /// @param execType The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). /// @return returnData An array containing the result of the delegatecall execution. function _handleDelegateCallExecutionAndReturnData( bytes calldata executionCalldata, ExecType execType ) internal returns (bytes[] memory returnData) { (address delegate, bytes calldata callData) = executionCalldata.decodeDelegateCall(); returnData = new bytes[](1); bool success; if (execType == EXECTYPE_DEFAULT) { returnData[0] = _executeDelegatecall(delegate, callData); } else if (execType == EXECTYPE_TRY) { (success, returnData[0]) = _tryExecuteDelegatecall(delegate, callData); if (!success) emit TryDelegateCallUnsuccessful(callData, returnData[0]); } else revert UnsupportedExecType(execType); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; import { IModule } from "./IModule.sol"; /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IValidator is IModule { /// @notice Validates a user operation as per ERC-4337 standard requirements. /// @dev Should ensure that the signature and nonce are verified correctly before the transaction is allowed to proceed. /// The function returns a status code indicating validation success or failure. /// @param userOp The user operation containing transaction details to be validated. /// @param userOpHash The hash of the user operation data, used for verifying the signature. /// @return status The result of the validation process, typically indicating success or the type of failure. function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256); /// @notice Verifies a signature against a hash, using the sender's address as a contextual check. /// @dev Used to confirm the validity of a signature against the specific conditions set by the sender. /// @param sender The address from which the operation was initiated, adding an additional layer of validation against the signature. /// @param hash The hash of the data signed. /// @param data The signature data to validate. /// @return magicValue A bytes4 value that corresponds to the ERC-1271 standard, indicating the validity of the signature. function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data) external view returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] // Magic value for ERC-1271 valid signature bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e; // Value indicating an invalid ERC-1271 signature bytes4 constant ERC1271_INVALID = 0xFFFFFFFF; // Value indicating successful validation uint256 constant VALIDATION_SUCCESS = 0; // Value indicating failed validation uint256 constant VALIDATION_FAILED = 1; // Module type identifier for Multitype install uint256 constant MODULE_TYPE_MULTI = 0; // Module type identifier for validators uint256 constant MODULE_TYPE_VALIDATOR = 1; // Module type identifier for executors uint256 constant MODULE_TYPE_EXECUTOR = 2; // Module type identifier for fallback handlers uint256 constant MODULE_TYPE_FALLBACK = 3; // Module type identifier for hooks uint256 constant MODULE_TYPE_HOOK = 4; string constant MODULE_ENABLE_MODE_NOTATION = "ModuleEnableMode(address module,uint256 moduleType,bytes32 userOpHash,bytes32 initDataHash)"; bytes32 constant MODULE_ENABLE_MODE_TYPE_HASH = keccak256(bytes(MODULE_ENABLE_MODE_NOTATION)); // Validation modes bytes1 constant MODE_VALIDATION = 0x00; bytes1 constant MODE_MODULE_ENABLE = 0x01; bytes4 constant SUPPORTS_ERC7739 = 0x77390000; bytes4 constant SUPPORTS_ERC7739_V1 = 0x77390001;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; /// @title ModeLib /// @author zeroknots.eth | rhinestone.wtf /// To allow smart accounts to be very simple, but allow for more complex execution, A custom mode /// encoding is used. /// Function Signature of execute function: /// function execute(ExecutionMode mode, bytes calldata executionCalldata) external payable; /// This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and /// context. /// NOTE: Simple Account implementations only have to scope for the most significant byte. Account that /// implement /// more complex execution modes may use the entire bytes32. /// /// |--------------------------------------------------------------------| /// | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload | /// |--------------------------------------------------------------------| /// | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes | /// |--------------------------------------------------------------------| /// /// CALLTYPE: 1 byte /// CallType is used to determine how the executeCalldata paramter of the execute function has to be /// decoded. /// It can be either single, batch or delegatecall. In the future different calls could be added. /// CALLTYPE can be used by a validation module to determine how to decode <userOp.callData[36:]>. /// /// EXECTYPE: 1 byte /// ExecType is used to determine how the account should handle the execution. /// It can indicate if the execution should revert on failure or continue execution. /// In the future more execution modes may be added. /// Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in /// a batch fails, the entire batch is reverted /// /// UNUSED: 4 bytes /// Unused bytes are reserved for future use. /// /// ModeSelector: bytes4 /// The "optional" mode selector can be used by account vendors, to implement custom behavior in /// their accounts. /// the way a ModeSelector is to be calculated is bytes4(keccak256("vendorname.featurename")) /// this is to prevent collisions between different vendors, while allowing innovation and the /// development of new features without coordination between ERC-7579 implementing accounts /// /// ModePayload: 22 bytes /// Mode payload is used to pass additional data to the smart account execution, this may be /// interpreted depending on the ModeSelector /// /// ExecutionCallData: n bytes /// single, delegatecall or batch exec abi.encoded as bytes // Custom type for improved developer experience type ExecutionMode is bytes32; type CallType is bytes1; type ExecType is bytes1; type ModeSelector is bytes4; type ModePayload is bytes22; // Default CallType CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); // Batched CallType CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); // @dev Implementing delegatecall is OPTIONAL! // implement delegatecall with extreme care. CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); // @dev default behavior is to revert on failure // To allow very simple accounts to use mode encoding, the default behavior is to revert on failure // Since this is value 0x00, no additional encoding is required for simple accounts ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); // @dev account may elect to change execution behavior. For example "try exec" / "allow fail" ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01); ModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000)); // Example declaration of a custom mode selector ModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256("default.mode.offset"))); /// @dev ModeLib is a helper library to encode/decode ModeCodes library ModeLib { function decode( ExecutionMode mode ) internal pure returns (CallType _calltype, ExecType _execType, ModeSelector _modeSelector, ModePayload _modePayload) { assembly { _calltype := mode _execType := shl(8, mode) _modeSelector := shl(48, mode) _modePayload := shl(80, mode) } } function decodeBasic(ExecutionMode mode) internal pure returns (CallType _calltype, ExecType _execType) { assembly { _calltype := mode _execType := shl(8, mode) } } function encode(CallType callType, ExecType execType, ModeSelector mode, ModePayload payload) internal pure returns (ExecutionMode) { return ExecutionMode.wrap(bytes32(abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload))); } function encodeSimpleBatch() internal pure returns (ExecutionMode mode) { mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); } function encodeSimpleSingle() internal pure returns (ExecutionMode mode) { mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); } function encodeTrySingle() internal pure returns (ExecutionMode mode) { mode = encode(CALLTYPE_SINGLE, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(0x00)); } function encodeTryBatch() internal pure returns (ExecutionMode mode) { mode = encode(CALLTYPE_BATCH, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(0x00)); } function encodeCustom(CallType callType, ExecType execType) internal pure returns (ExecutionMode mode) { mode = encode(callType, execType, MODE_DEFAULT, ModePayload.wrap(0x00)); } function getCallType(ExecutionMode mode) internal pure returns (CallType calltype) { assembly { calltype := mode } } } using { _eqModeSelector as == } for ModeSelector global; using { _eqCallType as == } for CallType global; using { _uneqCallType as != } for CallType global; using { _eqExecType as == } for ExecType global; function _eqCallType(CallType a, CallType b) pure returns (bool) { return CallType.unwrap(a) == CallType.unwrap(b); } function _uneqCallType(CallType a, CallType b) pure returns (bool) { return CallType.unwrap(a) != CallType.unwrap(b); } function _eqExecType(ExecType a, ExecType b) pure returns (bool) { return ExecType.unwrap(a) == ExecType.unwrap(b); } //slither-disable-next-line dead-code function _eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) { return ModeSelector.unwrap(a) == ModeSelector.unwrap(b); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.27; import { MODE_MODULE_ENABLE } from "../types/Constants.sol"; /** Nonce structure [3 bytes empty][1 bytes validation mode][20 bytes validator][8 bytes nonce] */ library NonceLib { /// @dev Parses validator address out of nonce /// @param nonce The nonce /// @return validator function getValidator(uint256 nonce) internal pure returns (address validator) { assembly { validator := shr(96, shl(32, nonce)) } } /// @dev Detects if Validaton Mode is Module Enable Mode /// @param nonce The nonce /// @return res boolean result, true if it is the Module Enable Mode function isModuleEnableMode(uint256 nonce) internal pure returns (bool res) { assembly { let vmode := byte(3, nonce) res := eq(shl(248, vmode), MODE_MODULE_ENABLE) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Sentinel address address constant SENTINEL = address(0x1); // Zero address address constant ZERO_ADDRESS = address(0x0); /** * @title SentinelListLib * @dev Library for managing a linked list of addresses * @author Rhinestone */ library SentinelListLib { // Struct to hold the linked list struct SentinelList { mapping(address => address) entries; } error LinkedList_AlreadyInitialized(); error LinkedList_InvalidPage(); error LinkedList_InvalidEntry(address entry); error LinkedList_EntryAlreadyInList(address entry); /** * Initialize the linked list * * @param self The linked list */ function init(SentinelList storage self) internal { if (alreadyInitialized(self)) revert LinkedList_AlreadyInitialized(); self.entries[SENTINEL] = SENTINEL; } /** * Check if the linked list is already initialized * * @param self The linked list * * @return bool True if the linked list is already initialized */ function alreadyInitialized(SentinelList storage self) internal view returns (bool) { return self.entries[SENTINEL] != ZERO_ADDRESS; } /** * Get the next entry in the linked list * * @param self The linked list * @param entry The current entry * * @return address The next entry */ function getNext(SentinelList storage self, address entry) internal view returns (address) { if (entry == ZERO_ADDRESS) { revert LinkedList_InvalidEntry(entry); } return self.entries[entry]; } /** * Push a new entry to the linked list * * @param self The linked list * @param newEntry The new entry */ function push(SentinelList storage self, address newEntry) internal { if (newEntry == ZERO_ADDRESS || newEntry == SENTINEL) { revert LinkedList_InvalidEntry(newEntry); } if (self.entries[newEntry] != ZERO_ADDRESS) revert LinkedList_EntryAlreadyInList(newEntry); self.entries[newEntry] = self.entries[SENTINEL]; self.entries[SENTINEL] = newEntry; } /** * Safe push a new entry to the linked list * @dev This ensures that the linked list is initialized and initializes it if it is not * * @param self The linked list * @param newEntry The new entry */ function safePush(SentinelList storage self, address newEntry) internal { if (!alreadyInitialized({ self: self })) { init({ self: self }); } push({ self: self, newEntry: newEntry }); } /** * Pop an entry from the linked list * * @param self The linked list * @param prevEntry The entry before the entry to pop * @param popEntry The entry to pop */ function pop(SentinelList storage self, address prevEntry, address popEntry) internal { if (popEntry == ZERO_ADDRESS || popEntry == SENTINEL) { revert LinkedList_InvalidEntry(prevEntry); } if (self.entries[prevEntry] != popEntry) revert LinkedList_InvalidEntry(popEntry); self.entries[prevEntry] = self.entries[popEntry]; self.entries[popEntry] = ZERO_ADDRESS; } /** * Pop all entries from the linked list * * @param self The linked list */ function popAll(SentinelList storage self) internal { address next = self.entries[SENTINEL]; while (next != ZERO_ADDRESS) { address current = next; next = self.entries[next]; self.entries[current] = ZERO_ADDRESS; } } /** * Check if the linked list contains an entry * * @param self The linked list * @param entry The entry to check * * @return bool True if the linked list contains the entry */ function contains(SentinelList storage self, address entry) internal view returns (bool) { return SENTINEL != entry && self.entries[entry] != ZERO_ADDRESS; } /** * Get all entries in the linked list * * @param self The linked list * @param start The start entry * @param pageSize The page size * * @return array All entries in the linked list * @return next The next entry */ function getEntriesPaginated( SentinelList storage self, address start, uint256 pageSize ) internal view returns (address[] memory array, address next) { if (start != SENTINEL && !contains(self, start)) revert LinkedList_InvalidEntry(start); if (pageSize == 0) revert LinkedList_InvalidPage(); // Init array with max page size array = new address[](pageSize); // Populate return array uint256 entryCount = 0; next = self.entries[start]; while (next != ZERO_ADDRESS && next != SENTINEL && entryCount < pageSize) { array[entryCount] = next; next = self.entries[next]; entryCount++; } /** * Because of the argument validation, we can assume that the loop will always iterate over * the valid entry list values * and the `next` variable will either be an enabled entry or a sentinel address * (signalling the end). * * If we haven't reached the end inside the loop, we need to set the next pointer to * the last element of the entry array * because the `next` variable (which is a entry by itself) acting as a pointer to the * start of the next page is neither * incSENTINELrent page, nor will it be included in the next one if you pass it as a * start. */ if (next != SENTINEL && entryCount > 0) { next = array[entryCount - 1]; } // Set correct size of returned array // solhint-disable-next-line no-inline-assembly /// @solidity memory-safe-assembly assembly { mstore(array, entryCount) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] /// @title Execution /// @notice Struct to encapsulate execution data for a transaction struct Execution { /// @notice The target address for the transaction address target; /// @notice The value in wei to send with the transaction uint256 value; /// @notice The calldata for the transaction bytes callData; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; /// @title Nexus - IERC4337Account /// @notice This interface defines the necessary validation and execution methods for smart accounts under the ERC-4337 standard. /// @dev Provides a structure for implementing custom validation logic and execution methods that comply with ERC-4337 "account abstraction" specs. /// The validation method ensures proper signature and nonce verification before proceeding with transaction execution, critical for securing userOps. /// Also allows for the optional definition of an execution method to handle transactions post-validation, enhancing flexibility. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IERC4337Account { /// 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 ERC-4337-v-0.7 validation stage /// @dev Must validate caller is the entryPoint. /// Must validate the signature and nonce /// @param userOp - The user 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); /// 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) /// @dev ERC-4337-v-0.7 optional execution path /// @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 payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IAccountConfig } from "./base/IAccountConfig.sol"; import { IExecutionHelper } from "./base/IExecutionHelper.sol"; import { IModuleManager } from "./base/IModuleManager.sol"; /// @title Nexus - IERC7579Account /// @notice This interface integrates the functionalities required for a modular smart account compliant with ERC-7579 and ERC-4337 standards. /// @dev Combines configurations and operational management for smart accounts, bridging IAccountConfig, IExecutionHelper, and IModuleManager. /// Interfaces designed to support the comprehensive management of smart account operations including execution management and modular configurations. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IERC7579Account is IAccountConfig, IExecutionHelper, IModuleManager { /// @dev Validates a smart account signature according to ERC-1271 standards. /// This method may delegate the call to a validator module to check the signature. /// @param hash The hash of the data being validated. /// @param data The signed data to validate. function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; /// @title Nexus - INexus Events and Errors /// @notice Defines common errors for the Nexus smart account management interface. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface INexusEventsAndErrors { /// @notice Emitted when a user operation is executed from `executeUserOp` /// @param userOp The user operation that was executed. /// @param innerCallRet The return data from the inner call execution. event Executed(PackedUserOperation userOp, bytes innerCallRet); /// @notice Error thrown when an unsupported ModuleType is requested. /// @param moduleTypeId The ID of the unsupported module type. error UnsupportedModuleType(uint256 moduleTypeId); /// @notice Error thrown on failed execution. error ExecutionFailed(); /// @notice Error thrown when the Factory fails to initialize the account with posted bootstrap data. error NexusInitializationFailed(); /// @notice Error thrown when a zero address is provided as the Entry Point address. error EntryPointCanNotBeZero(); /// @notice Error thrown when the provided implementation address is invalid. error InvalidImplementationAddress(); /// @notice Error thrown when the provided implementation address is not a contract. error ImplementationIsNotAContract(); /// @notice Error thrown when an inner call fails. error InnerCallFailed(); /// @notice Error thrown when attempted to emergency-uninstall a hook error EmergencyTimeLockNotExpired(); }
/** ** 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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IBaseAccountEventsAndErrors } from "./IBaseAccountEventsAndErrors.sol"; /// @title Nexus - IBaseAccount /// @notice Interface for the BaseAccount functionalities compliant with ERC-7579 and ERC-4337. /// @dev Interface for organizing the base functionalities using the Nexus suite. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IBaseAccount is IBaseAccountEventsAndErrors { /// @notice Adds deposit to the EntryPoint to fund transactions. function addDeposit() external payable; /// @notice Withdraws ETH from the EntryPoint to a specified address. /// @param to The address to receive the withdrawn funds. /// @param amount The amount to withdraw. function withdrawDepositTo(address to, uint256 amount) external payable; /// @notice Gets the nonce for a particular key. /// @param key The nonce key. /// @return The nonce associated with the key. function nonce(uint192 key) external view returns (uint256); /// @notice Returns the current deposit balance of this account on the EntryPoint. /// @return The current balance held at the EntryPoint. function getDeposit() external view returns (uint256); /// @notice Retrieves the address of the EntryPoint contract, currently using version 0.7. /// @return The address of the EntryPoint contract. function entryPoint() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IStorage } from "../interfaces/base/IStorage.sol"; /// @title Nexus - Storage /// @notice Manages isolated storage spaces for Modular Smart Account in compliance with ERC-7201 standard to ensure collision-resistant storage. /// @dev Implements the ERC-7201 namespaced storage pattern to maintain secure and isolated storage sections for different states within Nexus suite. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady contract Storage is IStorage { /// @custom:storage-location erc7201:biconomy.storage.Nexus /// ERC-7201 namespaced via `keccak256(abi.encode(uint256(keccak256(bytes("biconomy.storage.Nexus"))) - 1)) & ~bytes32(uint256(0xff));` bytes32 private constant _STORAGE_LOCATION = 0x0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f00; /// @dev Utilizes ERC-7201's namespaced storage pattern for isolated storage access. This method computes /// the storage slot based on a predetermined location, ensuring collision-resistant storage for contract states. /// @custom:storage-location ERC-7201 formula applied to "biconomy.storage.Nexus", facilitating unique /// namespace identification and storage segregation, as detailed in the specification. /// @return $ The proxy to the `AccountStorage` struct, providing a reference to the namespaced storage slot. function _getAccountStorage() internal pure returns (AccountStorage storage $) { assembly { $.slot := _STORAGE_LOCATION } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IModule } from "./IModule.sol"; /// @title Hook Management Interface /// @notice Provides methods for pre-checks and post-checks of transactions to ensure conditions and state consistency. /// @dev Defines two critical lifecycle hooks in the transaction process: `preCheck` and `postCheck`. /// These methods facilitate validating conditions prior to execution and verifying state changes afterwards, respectively. interface IHook is IModule { /// @notice Performs checks before a transaction is executed, potentially modifying the transaction context. /// @dev This method is called before the execution of a transaction to validate and possibly adjust execution context. /// @param msgSender The original sender of the transaction. /// @param msgValue The amount of wei sent with the call. /// @param msgData The calldata of the transaction. /// @return hookData Data that may be used or modified throughout the transaction lifecycle, passed to `postCheck`. function preCheck(address msgSender, uint256 msgValue, bytes calldata msgData) external returns (bytes memory hookData); /// @notice Performs checks after a transaction is executed to ensure state consistency and log results. /// @dev This method is called after the execution of a transaction to verify and react to the execution outcome. /// @param hookData Data returned from `preCheck`, containing execution context or modifications. function postCheck(bytes calldata hookData) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] /// @title Nexus - ERC-7579 Module Base Interface /// @notice Interface for module management in smart accounts, complying with ERC-7579 specifications. /// @dev Defines the lifecycle hooks and checks for modules within the smart account architecture. /// This interface includes methods for installing, uninstalling, and verifying module types and initialization status. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IModule { /// @notice Installs the module with necessary initialization data. /// @dev Reverts if the module is already initialized. /// @param data Arbitrary data required for initializing the module during `onInstall`. function onInstall(bytes calldata data) external; /// @notice Uninstalls the module and allows for cleanup via arbitrary data. /// @dev Reverts if any issues occur that prevent clean uninstallation. /// @param data Arbitrary data required for deinitializing the module during `onUninstall`. function onUninstall(bytes calldata data) external; /// @notice Determines if the module matches a specific module type. /// @dev Should return true if the module corresponds to the type ID, false otherwise. /// @param moduleTypeId Numeric ID of the module type as per ERC-7579 specifications. /// @return True if the module is of the specified type, false otherwise. function isModuleType(uint256 moduleTypeId) external view returns (bool); /// @notice Checks if the module has been initialized for a specific smart account. /// @dev Returns true if initialized, false otherwise. /// @param smartAccount Address of the smart account to check for initialization status. /// @return True if the module is initialized for the given smart account, false otherwise. function isInitialized(address smartAccount) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IModule } from "./IModule.sol"; /// @title Nexus - IExecutor Interface /// @notice Defines the interface for Executor modules within the Nexus Smart Account framework, compliant with the ERC-7579 standard. /// @dev Extends IModule to include functionalities specific to execution modules. /// This interface is future-proof, allowing for expansion and integration of advanced features in subsequent versions. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IExecutor is IModule { // Future methods for execution management will be defined here to accommodate evolving requirements. }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IModule } from "./IModule.sol"; /// @title Nexus - IFallback Interface /// @notice Defines the interface for Fallback modules within the Nexus Smart Account framework, compliant with the ERC-7579 standard. /// @dev Extends IModule to include functionalities specific to fallback modules. /// This interface is future-proof, allowing for expansion and integration of advanced features in subsequent versions. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IFallback is IModule { // Future methods for fallback management will be defined here to accommodate evolving blockchain technologies. }
// SPDX-License-Identifier: MIT pragma solidity 0.8.27; library LocalCallDataParserLib { /// @dev Parses the `userOp.signature` to extract the module type, module initialization data, /// enable mode signature, and user operation signature. The `userOp.signature` must be /// encoded in a specific way to be parsed correctly. /// @param packedData The packed signature data, typically coming from `userOp.signature`. /// @return module The address of the module. /// @return moduleType The type of module as a `uint256`. /// @return moduleInitData Initialization data specific to the module. /// @return enableModeSignature Signature used to enable the module mode. /// @return userOpSignature The remaining user operation signature data. function parseEnableModeData( bytes calldata packedData ) internal pure returns ( address module, uint256 moduleType, bytes calldata moduleInitData, bytes calldata enableModeSignature, bytes calldata userOpSignature ) { uint256 p; assembly ("memory-safe") { p := packedData.offset module := shr(96, calldataload(p)) p := add(p, 0x14) moduleType := calldataload(p) moduleInitData.length := shr(224, calldataload(add(p, 0x20))) moduleInitData.offset := add(p, 0x24) p := add(moduleInitData.offset, moduleInitData.length) enableModeSignature.length := shr(224, calldataload(p)) enableModeSignature.offset := add(p, 0x04) p := sub(add(enableModeSignature.offset, enableModeSignature.length), packedData.offset) } userOpSignature = packedData[p:]; } /// @dev Parses the data to obtain types and initdata's for Multi Type module install mode /// @param initData Multi Type module init data, abi.encoded function parseMultiTypeInitData(bytes calldata initData) internal pure returns (uint256[] calldata types, bytes[] calldata initDatas) { // equivalent of: // (types, initDatas) = abi.decode(initData,(uint[],bytes[])) assembly ("memory-safe") { let offset := initData.offset let baseOffset := offset let dataPointer := add(baseOffset, calldataload(offset)) types.offset := add(dataPointer, 32) types.length := calldataload(dataPointer) offset := add(offset, 32) dataPointer := add(baseOffset, calldataload(offset)) initDatas.offset := add(dataPointer, 32) initDatas.length := calldataload(dataPointer) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { CallType } from "../../lib/ModeLib.sol"; /// @title ERC-7579 Module Manager Events and Errors Interface /// @notice Provides event and error definitions for actions related to module management in smart accounts. /// @dev Used by IModuleManager to define the events and errors associated with the installation and management of modules. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IModuleManagerEventsAndErrors { /// @notice Emitted when a module is installed onto a smart account. /// @param moduleTypeId The identifier for the type of module installed. /// @param module The address of the installed module. event ModuleInstalled(uint256 moduleTypeId, address module); /// @notice Emitted when a module is uninstalled from a smart account. /// @param moduleTypeId The identifier for the type of module uninstalled. /// @param module The address of the uninstalled module. event ModuleUninstalled(uint256 moduleTypeId, address module); /// @notice Thrown when attempting to remove the last validator. error CanNotRemoveLastValidator(); /// @dev Thrown when the specified module address is not recognized as valid. error ValidatorNotInstalled(address module); /// @dev Thrown when there is no installed validator detected. error NoValidatorInstalled(); /// @dev Thrown when the specified module address is not recognized as valid. error InvalidModule(address module); /// @dev Thrown when an invalid module type identifier is provided. error InvalidModuleTypeId(uint256 moduleTypeId); /// @dev Thrown when there is an attempt to install a module that is already installed. error ModuleAlreadyInstalled(uint256 moduleTypeId, address module); /// @dev Thrown when an operation is performed by an unauthorized operator. error UnauthorizedOperation(address operator); /// @dev Thrown when there is an attempt to uninstall a module that is not installed. error ModuleNotInstalled(uint256 moduleTypeId, address module); /// @dev Thrown when a module address is set to zero. error ModuleAddressCanNotBeZero(); /// @dev Thrown when a post-check fails after hook execution. error HookPostCheckFailed(); /// @dev Thrown when there is an attempt to install a hook while another is already installed. error HookAlreadyInstalled(address currentHook); /// @dev Thrown when there is an attempt to install a fallback handler for a selector already having one. error FallbackAlreadyInstalledForSelector(bytes4 selector); /// @dev Thrown when there is an attempt to uninstall a fallback handler for a selector that does not have one installed. error FallbackNotInstalledForSelector(bytes4 selector); /// @dev Thrown when a fallback handler fails to uninstall properly. error FallbackHandlerUninstallFailed(); /// @dev Thrown when no fallback handler is available for a given selector. error MissingFallbackHandler(bytes4 selector); /// @dev Thrown when Invalid data is provided for MultiType install flow error InvalidInput(); /// @dev Thrown when unable to validate Module Enable Mode signature error EnableModeSigError(); /// Error thrown when account installs/uninstalls module with mismatched input `moduleTypeId` error MismatchModuleTypeId(uint256 moduleTypeId); /// @dev Thrown when there is an attempt to install a forbidden selector as a fallback handler. error FallbackSelectorForbidden(); /// @dev Thrown when there is an attempt to install a fallback handler with an invalid calltype for a given selector. error FallbackCallTypeInvalid(); /// @notice Error thrown when an execution with an unsupported CallType was made. /// @param callType The unsupported call type. error UnsupportedCallType(CallType callType); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Contract for EIP-712 typed structured data hashing and signing. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol) /// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol) /// /// @dev Note, this implementation: /// - Uses `address(this)` for the `verifyingContract` field. /// - Does NOT use the optional EIP-712 salt. /// - Does NOT use any EIP-712 extensions. /// This is for simplicity and to save gas. /// If you need to customize, please fork / modify accordingly. abstract contract EIP712 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. bytes32 internal constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; uint256 private immutable _cachedThis; uint256 private immutable _cachedChainId; bytes32 private immutable _cachedNameHash; bytes32 private immutable _cachedVersionHash; bytes32 private immutable _cachedDomainSeparator; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Cache the hashes for cheaper runtime gas costs. /// In the case of upgradeable contracts (i.e. proxies), /// or if the chain id changes due to a hard fork, /// the domain separator will be seamlessly calculated on-the-fly. constructor() { _cachedThis = uint256(uint160(address(this))); _cachedChainId = block.chainid; string memory name; string memory version; if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion(); bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name)); bytes32 versionHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version)); _cachedNameHash = nameHash; _cachedVersionHash = versionHash; bytes32 separator; if (!_domainNameAndVersionMayChange()) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Load the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), nameHash) mstore(add(m, 0x40), versionHash) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) separator := keccak256(m, 0xa0) } } _cachedDomainSeparator = separator; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FUNCTIONS TO OVERRIDE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Please override this function to return the domain name and version. /// ``` /// function _domainNameAndVersion() /// internal /// pure /// virtual /// returns (string memory name, string memory version) /// { /// name = "Solady"; /// version = "1"; /// } /// ``` /// /// Note: If the returned result may change after the contract has been deployed, /// you must override `_domainNameAndVersionMayChange()` to return true. function _domainNameAndVersion() internal view virtual returns (string memory name, string memory version); /// @dev Returns if `_domainNameAndVersion()` may change /// after the contract has been deployed (i.e. after the constructor). /// Default: false. function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the EIP-712 domain separator. function _domainSeparator() internal view virtual returns (bytes32 separator) { if (_domainNameAndVersionMayChange()) { separator = _buildDomainSeparator(); } else { separator = _cachedDomainSeparator; if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator(); } } /// @dev Returns the hash of the fully encoded EIP-712 message for this domain, /// given `structHash`, as defined in /// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. /// /// The hash can be used together with {ECDSA-recover} to obtain the signer of a message: /// ``` /// bytes32 digest = _hashTypedData(keccak256(abi.encode( /// keccak256("Mail(address to,string contents)"), /// mailTo, /// keccak256(bytes(mailContents)) /// ))); /// address signer = ECDSA.recover(digest, signature); /// ``` function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) { // We will use `digest` to store the domain separator to save a bit of gas. if (_domainNameAndVersionMayChange()) { digest = _buildDomainSeparator(); } else { digest = _cachedDomainSeparator; if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator(); } /// @solidity memory-safe-assembly assembly { // Compute the digest. mstore(0x00, 0x1901000000000000) // Store "\x19\x01". mstore(0x1a, digest) // Store the domain separator. mstore(0x3a, structHash) // Store the struct hash. digest := keccak256(0x18, 0x42) // Restore the part of the free memory slot that was overwritten. mstore(0x3a, 0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EIP-5267 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev See: https://eips.ethereum.org/EIPS/eip-5267 function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { fields = hex"0f"; // `0b01111`. (name, version) = _domainNameAndVersion(); chainId = block.chainid; verifyingContract = address(this); salt = salt; // `bytes32(0)`. extensions = extensions; // `new uint256[](0)`. } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the EIP-712 domain separator. function _buildDomainSeparator() private view returns (bytes32 separator) { // We will use `separator` to store the name hash to save a bit of gas. bytes32 versionHash; if (_domainNameAndVersionMayChange()) { (string memory name, string memory version) = _domainNameAndVersion(); separator = keccak256(bytes(name)); versionHash = keccak256(bytes(version)); } else { separator = _cachedNameHash; versionHash = _cachedVersionHash; } /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Load the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), separator) // Name hash. mstore(add(m, 0x40), versionHash) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) separator := keccak256(m, 0xa0) } } /// @dev Returns if the cached domain separator has been invalidated. function _cachedDomainSeparatorInvalidated() private view returns (bool result) { uint256 cachedChainId = _cachedChainId; uint256 cachedThis = _cachedThis; /// @solidity memory-safe-assembly assembly { result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis))) } } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.7.6; library ExcessivelySafeCall { uint256 constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff; /// @notice Use when you _really_ really _really_ don't trust the called /// contract. This prevents the called contract from causing reversion of /// the caller in as many ways as we can. /// @dev The main difference between this and a solidity low-level call is /// that we limit the number of bytes that the callee can cause to be /// copied to caller memory. This prevents stupid things like malicious /// contracts returning 10,000,000 bytes causing a local OOG when copying /// to memory. /// @param _target The address to call /// @param _gas The amount of gas to forward to the remote contract /// @param _value The value in wei to send to the remote contract /// @param _maxCopy The maximum number of bytes of returndata to copy /// to memory. /// @param _calldata The data to send to the remote contract /// @return success and returndata, as `.call()`. Returndata is capped to /// `_maxCopy` bytes. function excessivelySafeCall( address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata ) internal returns (bool, bytes memory) { // set up for assembly call uint256 _toCopy; bool _success; bytes memory _returnData = new bytes(_maxCopy); // dispatch message to recipient // by assembly calling "handle" function // we call via assembly to avoid memcopying a very large returndata // returned by a malicious contract assembly { _success := call( _gas, // gas _target, // recipient _value, // ether value add(_calldata, 0x20), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) // limit our copy to 256 bytes _toCopy := returndatasize() if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy } // Store the length of the copied bytes mstore(_returnData, _toCopy) // copy the bytes from returndata[0:_toCopy] returndatacopy(add(_returnData, 0x20), 0, _toCopy) } return (_success, _returnData); } /// @notice Use when you _really_ really _really_ don't trust the called /// contract. This prevents the called contract from causing reversion of /// the caller in as many ways as we can. /// @dev The main difference between this and a solidity low-level call is /// that we limit the number of bytes that the callee can cause to be /// copied to caller memory. This prevents stupid things like malicious /// contracts returning 10,000,000 bytes causing a local OOG when copying /// to memory. /// @param _target The address to call /// @param _gas The amount of gas to forward to the remote contract /// @param _maxCopy The maximum number of bytes of returndata to copy /// to memory. /// @param _calldata The data to send to the remote contract /// @return success and returndata, as `.call()`. Returndata is capped to /// `_maxCopy` bytes. function excessivelySafeStaticCall( address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata ) internal view returns (bool, bytes memory) { // set up for assembly call uint256 _toCopy; bool _success; bytes memory _returnData = new bytes(_maxCopy); // dispatch message to recipient // by assembly calling "handle" function // we call via assembly to avoid memcopying a very large returndata // returned by a malicious contract assembly { _success := staticcall( _gas, // gas _target, // recipient add(_calldata, 0x20), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) // limit our copy to 256 bytes _toCopy := returndatasize() if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy } // Store the length of the copied bytes mstore(_returnData, _toCopy) // copy the bytes from returndata[0:_toCopy] returndatacopy(add(_returnData, 0x20), 0, _toCopy) } return (_success, _returnData); } /** * @notice Swaps function selectors in encoded contract calls * @dev Allows reuse of encoded calldata for functions with identical * argument types but different names. It simply swaps out the first 4 bytes * for the new selector. This function modifies memory in place, and should * only be used with caution. * @param _newSelector The new 4-byte selector * @param _buf The encoded contract args */ function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure { require(_buf.length >= 4); uint256 _mask = LOW_28_MASK; assembly { // load the first word of let _word := mload(add(_buf, 0x20)) // mask out the top 4 bytes // /x _word := and(_word, _mask) _word := or(_newSelector, _word) mstore(add(_buf, 0x20), _word) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import { IERC7484 } from "../interfaces/IERC7484.sol"; /// @title RegistryAdapter /// @notice This contract provides an interface for interacting with an ERC-7484 compliant registry. /// @dev The registry feature is opt-in, allowing the smart account owner to select and trust specific attesters. abstract contract RegistryAdapter { IERC7484 public registry; /// @notice Emitted when a new ERC-7484 registry is configured for the account. /// @param registry The configured registry contract. event ERC7484RegistryConfigured(IERC7484 indexed registry); /// @notice Modifier to check if a module meets the required attestations in the registry. /// @param module The module to check. /// @param moduleType The type of the module to verify in the registry. modifier withRegistry(address module, uint256 moduleType) { _checkRegistry(module, moduleType); _; } /// @notice Configures the ERC-7484 registry and sets trusted attesters. /// @param newRegistry The new registry contract to use. /// @param attesters The list of attesters to trust. /// @param threshold The number of attestations required. function _configureRegistry(IERC7484 newRegistry, address[] calldata attesters, uint8 threshold) internal { registry = newRegistry; if (address(newRegistry) != address(0)) { newRegistry.trustAttesters(threshold, attesters); } emit ERC7484RegistryConfigured(newRegistry); } /// @notice Checks the registry to ensure sufficient valid attestations for a module. /// @param module The module to check. /// @param moduleType The type of the module to verify in the registry. /// @dev Reverts if the required attestations are not met. function _checkRegistry(address module, uint256 moduleType) internal view { IERC7484 moduleRegistry = registry; if (address(moduleRegistry) != address(0)) { // This will revert if attestations or the threshold are not met. moduleRegistry.check(module, moduleType); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { ExecutionMode } from "../../lib/ModeLib.sol"; import { IExecutionHelperEventsAndErrors } from "./IExecutionHelperEventsAndErrors.sol"; /// @title Nexus - IExecutionHelper /// @notice Interface for executing transactions on behalf of smart accounts within the Nexus system. /// @dev Extends functionality for transaction execution with error handling as defined in IExecutionHelperEventsAndErrors. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IExecutionHelper is IExecutionHelperEventsAndErrors { /// @notice Executes a transaction with specified execution mode and calldata. /// @param mode The execution mode, defining how the transaction is processed. /// @param executionCalldata The calldata to execute. /// @dev This function ensures that the execution complies with smart account execution policies and handles errors appropriately. function execute(ExecutionMode mode, bytes calldata executionCalldata) external payable; /// @notice Allows an executor module to perform transactions on behalf of the account. /// @param mode The execution mode that details how the transaction should be handled. /// @param executionCalldata The transaction data to be executed. /// @return returnData The result of the execution, allowing for error handling and results interpretation by the executor module. function executeFromExecutor(ExecutionMode mode, bytes calldata executionCalldata) external payable returns (bytes[] memory returnData); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { ExecutionMode } from "../../lib/ModeLib.sol"; /// @title Nexus - ERC-7579 Account Configuration Interface /// @notice Interface for querying and verifying configurations of Smart Accounts compliant with ERC-7579. /// @dev Provides methods to check supported execution modes and module types for Smart Accounts, ensuring flexible and extensible configuration. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IAccountConfig { /// @notice Returns the account ID in a structured format: "vendorname.accountname.semver" /// @return accountImplementationId The account ID of the smart account function accountId() external view returns (string memory accountImplementationId); /// @notice Checks if the account supports a certain execution mode. /// @param encodedMode The encoded mode to verify. /// @return supported True if the account supports the mode, false otherwise. function supportsExecutionMode(ExecutionMode encodedMode) external view returns (bool supported); /// @notice Checks if the account supports a specific module type. /// @param moduleTypeId The module type ID to verify. /// @return supported True if the account supports the module type, false otherwise. function supportsModule(uint256 moduleTypeId) external view returns (bool supported); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { IModuleManagerEventsAndErrors } from "./IModuleManagerEventsAndErrors.sol"; /// @title Nexus - IModuleManager /// @notice Interface for managing modules within Smart Accounts, providing methods for installation and removal of modules. /// @dev Extends the IModuleManagerEventsAndErrors interface to include event and error definitions. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IModuleManager is IModuleManagerEventsAndErrors { /// @notice Installs a Module of a specific type onto the smart account. /// @param moduleTypeId The identifier for the module type. /// @param module The address of the module to be installed. /// @param initData Initialization data for configuring the module upon installation. function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable; /// @notice Uninstalls a Module of a specific type from the smart account. /// @param moduleTypeId The identifier for the module type being uninstalled. /// @param module The address of the module to uninstall. /// @param deInitData De-initialization data for configuring the module upon uninstallation. function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable; /// @notice Checks if a specific module is installed on the smart account. /// @param moduleTypeId The module type identifier to check. /// @param module The address of the module. /// @param additionalContext Additional information that may be required to verify the module's installation. /// @return installed True if the module is installed, false otherwise. function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) external view returns (bool installed); }
// 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: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] /// @title Execution Manager Events and Errors Interface /// @notice Interface for defining events and errors related to transaction execution processes within smart accounts. /// @dev This interface defines events and errors used by execution manager to handle and report the operational status of smart account transactions. /// It is a part of the Nexus suite of contracts aimed at implementing flexible and secure smart account operations. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IBaseAccountEventsAndErrors { /// @dev Throws an error when a caller is not authorized to access an account. error AccountAccessUnauthorized(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] import { SentinelListLib } from "sentinellist/SentinelList.sol"; import { IHook } from "../modules/IHook.sol"; import { CallType } from "../../lib/ModeLib.sol"; /// @title Nexus - IStorage Interface /// @notice Provides structured storage for Modular Smart Account under the Nexus suite, compliant with ERC-7579 and ERC-4337. /// @dev Manages structured storage using SentinelListLib for validators and executors, and a mapping for fallback handlers. /// This interface utilizes ERC-7201 storage location practices to ensure isolated and collision-resistant storage spaces within smart contracts. /// It is designed to support dynamic execution and modular management strategies essential for advanced smart account architectures. /// @custom:storage-location erc7201:biconomy.storage.Nexus /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady interface IStorage { /// @notice Struct storing validators and executors using Sentinel lists, and fallback handlers via mapping. struct AccountStorage { SentinelListLib.SentinelList validators; ///< List of validators, initialized upon contract deployment. SentinelListLib.SentinelList executors; ///< List of executors, similarly initialized. mapping(bytes4 => FallbackHandler) fallbacks; ///< Mapping of selectors to their respective fallback handlers. IHook hook; ///< Current hook module associated with this account. mapping(address hook => uint256) emergencyUninstallTimelock; ///< Mapping of hooks to requested timelocks. } /// @notice Defines a fallback handler with an associated handler address and a call type. struct FallbackHandler { address handler; ///< The address of the fallback function handler. CallType calltype; ///< The type of call this handler supports (e.g., static or call). } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; // ────────────────────────────────────────────────────────────────────────────── // _ __ _ __ // / | / /__ | |/ /_ _______ // / |/ / _ \| / / / / ___/ // / /| / __/ / /_/ (__ ) // /_/ |_/\___/_/|_\__,_/____/ // // ────────────────────────────────────────────────────────────────────────────── // Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy. // Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected] /// @title Execution Manager Events and Errors Interface /// @notice Interface for defining events and errors related to transaction execution processes within smart accounts. /// @dev This interface defines events and errors used by execution manager to handle and report the operational status of smart account transactions. /// It is a part of the Nexus suite of contracts aimed at implementing flexible and secure smart account operations. /// @author @livingrockrises | Biconomy | [email protected] /// @author @aboudjem | Biconomy | [email protected] /// @author @filmakarov | Biconomy | [email protected] /// @author @zeroknots | Rhinestone.wtf | zeroknots.eth /// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady import { ExecType } from "../../lib/ModeLib.sol"; interface IExecutionHelperEventsAndErrors { /// @notice Event emitted when a transaction fails to execute successfully. event TryExecuteUnsuccessful(bytes callData, bytes result); /// @notice Event emitted when a transaction fails to execute successfully. event TryDelegateCallUnsuccessful(bytes callData, bytes result); /// @notice Error thrown when an execution with an unsupported ExecType was made. /// @param execType The unsupported execution type. error UnsupportedExecType(ExecType execType); }
{ "remappings": [ "@openzeppelin/=node_modules/@openzeppelin/", "forge-std/=node_modules/forge-std/src/", "account-abstraction/=node_modules/account-abstraction/contracts/", "solady/=node_modules/solady/src/", "excessively-safe-call/=node_modules/excessively-safe-call/src/", "sentinellist/=node_modules/sentinellist/src/", "solarray/=node_modules/solarray/src/", "erc7739Validator/=node_modules/erc7739-validator-base/src/", "@ERC4337/=node_modules/@ERC4337/", "@gnosis.pm/=node_modules/@gnosis.pm/", "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "@prb/=node_modules/@prb/", "@prb/math/=node_modules/erc7739-validator-base/node_modules/@prb/math/src/", "@rhinestone/=node_modules/@rhinestone/", "@safe-global/=node_modules/@safe-global/", "@zerodev/=node_modules/@zerodev/", "ExcessivelySafeCall/=node_modules/erc7739-validator-base/node_modules/excessively-safe-call/src/", "account-abstraction-v0.6/=node_modules/account-abstraction-v0.6/", "ds-test/=node_modules/ds-test/", "enumerablemap/=node_modules/enumerablemap/", "enumerableset4337/=node_modules/erc7739-validator-base/node_modules/enumerablemap/src/", "erc4337-validation/=node_modules/erc7739-validator-base/node_modules/@rhinestone/erc4337-validation/src/", "erc7579/=node_modules/erc7579/", "erc7739-validator-base/=node_modules/erc7739-validator-base/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/", "kernel/=node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/", "module-bases/=node_modules/erc7739-validator-base/node_modules/@rhinestone/module-bases/src/", "modulekit/=node_modules/modulekit/", "registry/=node_modules/modulekit/node_modules/@rhinestone/registry/src/", "safe7579/=node_modules/erc7739-validator-base/node_modules/@rhinestone/safe7579/src/", "stringutils/=node_modules/stringutils/" ], "optimizer": { "enabled": true, "runs": 999 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"anEntryPoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountAccessUnauthorized","type":"error"},{"inputs":[],"name":"CanNotRemoveLastValidator","type":"error"},{"inputs":[],"name":"EmergencyTimeLockNotExpired","type":"error"},{"inputs":[],"name":"EnableModeSigError","type":"error"},{"inputs":[],"name":"EntryPointCanNotBeZero","type":"error"},{"inputs":[],"name":"ExecutionFailed","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"FallbackAlreadyInstalledForSelector","type":"error"},{"inputs":[],"name":"FallbackCallTypeInvalid","type":"error"},{"inputs":[],"name":"FallbackHandlerUninstallFailed","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"FallbackNotInstalledForSelector","type":"error"},{"inputs":[],"name":"FallbackSelectorForbidden","type":"error"},{"inputs":[{"internalType":"address","name":"currentHook","type":"address"}],"name":"HookAlreadyInstalled","type":"error"},{"inputs":[],"name":"HookPostCheckFailed","type":"error"},{"inputs":[],"name":"ImplementationIsNotAContract","type":"error"},{"inputs":[],"name":"InnerCallFailed","type":"error"},{"inputs":[],"name":"InvalidImplementationAddress","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"InvalidModule","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"InvalidModuleTypeId","type":"error"},{"inputs":[],"name":"LinkedList_AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"address","name":"entry","type":"address"}],"name":"LinkedList_EntryAlreadyInList","type":"error"},{"inputs":[{"internalType":"address","name":"entry","type":"address"}],"name":"LinkedList_InvalidEntry","type":"error"},{"inputs":[],"name":"LinkedList_InvalidPage","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"MismatchModuleTypeId","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"MissingFallbackHandler","type":"error"},{"inputs":[],"name":"ModuleAddressCanNotBeZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"}],"name":"ModuleAlreadyInstalled","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"}],"name":"ModuleNotInstalled","type":"error"},{"inputs":[],"name":"NexusInitializationFailed","type":"error"},{"inputs":[],"name":"NoValidatorInstalled","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"UnauthorizedOperation","type":"error"},{"inputs":[{"internalType":"CallType","name":"callType","type":"bytes1"}],"name":"UnsupportedCallType","type":"error"},{"inputs":[{"internalType":"ExecType","name":"execType","type":"bytes1"}],"name":"UnsupportedExecType","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"UnsupportedModuleType","type":"error"},{"inputs":[],"name":"UpgradeFailed","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"ValidatorNotInstalled","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC7484","name":"registry","type":"address"}],"name":"ERC7484RegistryConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hook","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"EmergencyHookUninstallRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hook","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"EmergencyHookUninstallRequestReset","type":"event"},{"anonymous":false,"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"}],"indexed":false,"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"},{"indexed":false,"internalType":"bytes","name":"innerCallRet","type":"bytes"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"ModuleInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"ModuleUninstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"result","type":"bytes"}],"name":"TryDelegateCallUnsuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"result","type":"bytes"}],"name":"TryExecuteUnsuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accountId","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"addDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"checkERC7739Support","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hook","type":"address"},{"internalType":"bytes","name":"deInitData","type":"bytes"}],"name":"emergencyUninstallHook","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ExecutionMode","name":"mode","type":"bytes32"},{"internalType":"bytes","name":"executionCalldata","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ExecutionMode","name":"mode","type":"bytes32"},{"internalType":"bytes","name":"executionCalldata","type":"bytes"}],"name":"executeFromExecutor","outputs":[{"internalType":"bytes[]","name":"returnData","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":"payable","type":"function"},{"inputs":[],"name":"getActiveHook","outputs":[{"internalType":"address","name":"hook","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeposit","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cursor","type":"address"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"getExecutorsPaginated","outputs":[{"internalType":"address[]","name":"array","type":"address[]"},{"internalType":"address","name":"next","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"getFallbackHandlerBySelector","outputs":[{"internalType":"CallType","name":"","type":"bytes1"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getImplementation","outputs":[{"internalType":"address","name":"implementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cursor","type":"address"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"getValidatorsPaginated","outputs":[{"internalType":"address[]","name":"array","type":"address[]"},{"internalType":"address","name":"next","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"structHash","type":"bytes32"}],"name":"hashTypedData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"initData","type":"bytes"}],"name":"initializeAccount","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"initData","type":"bytes"}],"name":"installModule","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"additionalContext","type":"bytes"}],"name":"isModuleInstalled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"uint192","name":"key","type":"uint192"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IERC7484","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC7484","name":"newRegistry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"setRegistry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ExecutionMode","name":"mode","type":"bytes32"}],"name":"supportsExecutionMode","outputs":[{"internalType":"bool","name":"isSupported","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"supportsModule","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"deInitData","type":"bytes"}],"name":"uninstallModule","outputs":[],"stateMutability":"payable","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":"op","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"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawDepositTo","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101606040523061014052348015610015575f5ffd5b50604051615734380380615734833981016040819052610034916101d4565b306080524660a05260608061007d6040805180820182526005808252644e6578757360d81b602080840191909152835180850190945290835264312e302e3160d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152938401929092529082015246606082015230608082015260a090206101005250506001600160a01b038116610107576040516307e355bf60e31b815260040160405180910390fd5b6001600160a01b0381166101205261011d610123565b50610201565b7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0061016d7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01610179565b61017681610179565b50565b60015f908152602082905260409020546001600160a01b0316156101b0576040516329e42f3360e11b815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b5f602082840312156101e4575f5ffd5b81516001600160a01b03811681146101fa575f5ffd5b9392505050565b60805160a05160c05160e05161010051610120516101405161545d6102d75f395f81816110ad015261269901525f818161062a01528181610adf01528181610d1601528181610e4301528181610e8e015281816111f001528181611500015281816115a601528181611a7701528181611ac701528181612033015281816120af015281816122c401526136d401525f818161250d015261278b01525f81816125c7015261284501525f81816125a1015261281f01525f818161255101526127cf01525f818161252e01526127ac015261545d5ff3fe6080604052600436106101db575f3560e01c80638dd7712f11610101578063cd64f80a11610094578063e9ae5c5311610063578063e9ae5c53146106f2578063ea5f61d014610705578063eab77e1714610724578063f2dc691d14610737576101e2565b8063cd64f80a14610681578063d03c791414610694578063d691c964146106b3578063d86f2b3c146106d3576101e2565b8063aaf10f42116100d0578063aaf10f4214610608578063b0d691fe1461061c578063b46b61a91461064e578063c399ec881461066d576101e2565b80638dd7712f146105845780639517e29f146105975780639cfd7cff146105aa578063a71763a8146105f5576101e2565b80634b6a1419116101795780635faac46b116101485780635faac46b146104f35780636575f6aa146105205780637b1039991461053f57806384b0196e1461055d576101e2565b80634b6a1419146104a65780634d44560d146104b95780634f1ef286146104cc57806352d1902d146104df576101e2565b806319822f7c116101b557806319822f7c146103a95780633644e515146103d6578063481ddd23146103ea5780634a58db191461049c576101e2565b80630a664dba14610311578063112d3a7d146103425780631626ba7e14610371576101e2565b366101e257005b5f3660605f6102055f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166102265761021f8484610756565b9150610305565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061025a9033903490869036906004016146dd565b5f604051808303815f875af1158015610275573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261029c91908101906147a5565b90506102a88585610756565b9250604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906102d690849060040161484d565b5f604051808303815f87803b1580156102ed575f5ffd5b505af11580156102ff573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b34801561031c575f5ffd5b5061032561096f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561034d575f5ffd5b5061036161035c3660046148c3565b610993565b6040519015158152602001610339565b34801561037c575f5ffd5b5061039061038b36600461491b565b6109ab565b6040516001600160e01b03199091168152602001610339565b3480156103b4575f5ffd5b506103c86103c336600461497a565b610ad2565b604051908152602001610339565b3480156103e1575f5ffd5b506103c8610d0b565b3480156103f5575f5ffd5b506104746104043660046149d9565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b03909116602083015201610339565b6104a4610d14565b005b6104a46104b43660046149f4565b610d48565b6104a46104c7366004614a27565b610e38565b6104a46104da366004614a51565b610eed565b3480156104ea575f5ffd5b506103c86110aa565b3480156104fe575f5ffd5b5061051261050d366004614a27565b611107565b604051610339929190614a89565b34801561052b575f5ffd5b506103c861053a366004614ae8565b61112d565b34801561054a575f5ffd5b505f54610325906001600160a01b031681565b348015610568575f5ffd5b5061057161113d565b6040516103399796959493929190614aff565b6104a4610592366004614b99565b6111e5565b6104a46105a53660046148c3565b6114f5565b3480156105b5575f5ffd5b50604080518082018252601481527f6269636f6e6f6d792e6e657875732e312e302e3000000000000000000000000060208201529051610339919061484d565b6104a46106033660046148c3565b61159b565b348015610613575f5ffd5b5061032561189c565b348015610627575f5ffd5b507f0000000000000000000000000000000000000000000000000000000000000000610325565b348015610659575f5ffd5b5061039061066836600461491b565b6118d3565b348015610678575f5ffd5b506103c8611a73565b6104a461068f366004614a51565b611abc565b34801561069f575f5ffd5b506103616106ae366004614ae8565b611cf7565b6106c66106c136600461491b565b611d65565b6040516103399190614bdb565b3480156106de575f5ffd5b506103c86106ed366004614c3e565b611fe3565b6104a461070036600461491b565b6120a4565b348015610710575f5ffd5b5061051261071f366004614a27565b61228b565b6104a4610732366004614c75565b6122b9565b348015610742575f5ffd5b50610361610751366004614ae8565b612318565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b81156108d3576001600160f81b03198116607f60f91b0361082c57816001600160a01b03166107d88888612372565b6040516107e59190614d10565b5f60405180830381855afa9150503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b606091505b50955093506108c1565b6001600160f81b0319811661089757816001600160a01b0316346108508989612372565b60405161085d9190614d10565b5f6040518083038185875af1925050503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b604051632e5bf3f960e21b81526001600160f81b0319821660048201526024015b60405180910390fd5b836108ce57845160208601fd5b610965565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561091257600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f351685610962576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b50505b5050505092915050565b5f61098e5f5160206153d65f395f51905f52546001600160a01b031690565b905090565b5f6109a0858585856123a7565b90505b949350505050565b5f8181036109e4576109c061ffff8319614d3a565b6109cc90617739614d59565b84036109e4576109dd8484846118d3565b9050610acb565b5f6109f26014828587614d70565b6109fb91614d97565b60601c9050610a0981612466565b8190610a345760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b506001600160a01b03811663f551e2ee3387610a53876014818b614d70565b6040518563ffffffff1660e01b8152600401610a7294939291906146dd565b602060405180830381865afa925050508015610aab575060408051601f3d908101601f19168201909252610aa891810190614de4565b60015b610ac057506001600160e01b03199050610acb565b9150610acb9050565b505b9392505050565b5f81336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b1d57604051635629665f60e11b815260040160405180910390fd5b5f602086013560401c6001600160a01b03169050600160f81b602087013560031a60f81b03610c4d575f610b5087614e4c565b9050610b6986610b646101008a018a614f4c565b61247e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505050610100820152610bab82612466565b8290610bd65760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b50604051639700320360e01b81526001600160a01b03831690639700320390610c059084908a90600401614f8f565b6020604051808303815f875af1158015610c21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c45919061505b565b935050610cf3565b610c5681612466565b8190610c815760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b50604051639700320360e01b81526001600160a01b03821690639700320390610cb09089908990600401615189565b6020604051808303815f875af1158015610ccc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf0919061505b565b92505b508015610ac9575f385f3884335af150509392505050565b5f61098e61250b565b7f00000000000000000000000000000000000000000000000000000000000000005f38818134855af1610d45575f38fd5b50565b610d50612600565b5f80610d5e838501856151aa565b915091505f826001600160a01b031682604051610d7b9190614d10565b5f60405180830381855af49150503d805f8114610db3576040519150601f19603f3d011682016040523d82523d5f602084013e610db8565b606091505b5050905080610df3576040517f315927c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dfb612640565b610e31576040517fc4d0a0b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610e6e57503330145b610e8b57604051635629665f60e11b815260040160405180910390fd5b5f7f0000000000000000000000000000000000000000000000000000000000000000905060405183601452826034526f205c28780000000000000000000000005f525f38604460105f865af1610ee3573d5f823e3d81fd5b505f603452505050565b5f610f0c5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b038116610f79576001600160a01b038416610f435760405163325c055b60e21b815260040160405180910390fd5b833b151580610f655760405163325c055b60e21b815260040160405180910390fd5b843055610f73858585612697565b506110a4565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590610fad9033903490869036906004016146dd565b5f604051808303815f875af1158015610fc8573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610fef91908101906147a5565b90506001600160a01b0385166110185760405163325c055b60e21b815260040160405180910390fd5b843b15158061103a5760405163325c055b60e21b815260040160405180910390fd5b853055611048868686612697565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061107590849060040161484d565b5f604051808303815f87803b15801561108c575f5ffd5b505af115801561109e573d5f5f3e3d5ffd5b50505050505b50505050565b5f7f00000000000000000000000000000000000000000000000000000000000000003081146110e057639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b60605f6111225f5160206153b65f395f51905f52858561276f565b909590945092505050565b5f61113782612789565b92915050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f8080836111d360408051808201825260058082527f4e6578757300000000000000000000000000000000000000000000000000000060208084019190915283518085019094529083527f312e302e310000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461122e57604051635629665f60e11b815260040160405180910390fd5b5f61124d5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b03811661135b57365f61126c6060860186614f4c565b61127a916004908290614d70565b915091505f5f306001600160a01b0316848460405161129a9291906151f7565b5f60405180830381855af49150503d805f81146112d2576040519150601f19603f3d011682016040523d82523d5f602084013e6112d7565b606091505b50915091508115611320577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f8782604051611313929190615206565b60405180910390a1611352565b6040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061138f9033903490869036906004016146dd565b5f604051808303815f875af11580156113aa573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113d191908101906147a5565b9050365f6113e26060870187614f4c565b6113f0916004908290614d70565b915091505f5f306001600160a01b031684846040516114109291906151f7565b5f60405180830381855af49150503d805f8114611448576040519150601f19603f3d011682016040523d82523d5f602084013e61144d565b606091505b50915091508115611320577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f8882604051611489929190615206565b60405180910390a15050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da91506114c190849060040161484d565b5f604051808303815f87803b1580156114d8575f5ffd5b505af11580156114ea573d5f5f3e3d5ffd5b50505050505b505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061152b57503330145b61154857604051635629665f60e11b815260040160405180910390fd5b6115548484848461289f565b604080518581526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123910160405180910390a150505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806115d157503330145b6115ee57604051635629665f60e11b815260040160405180910390fd5b5f61160d5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166116f057611629858585856123a7565b8585909161165c57604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518681526001600160a01b03861660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a1600185036116b7576116b2848484612a84565b610e31565b600285036116ca576116b2848484612b52565b600385036116dd576116b2848484612beb565b600485036116b2576116b2848484612cf2565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906117249033903490869036906004016146dd565b5f604051808303815f875af115801561173f573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261176691908101906147a5565b9050611774868686866123a7565b868690916117a757604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a160018603611802576117fd858585612a84565b61183b565b60028603611815576117fd858585612b52565b60038603611828576117fd858585612beb565b6004860361183b5761183b858585612cf2565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061186790849060040161484d565b5f604051808303815f87803b15801561187e575f5ffd5b505af1158015611890573d5f5f3e3d5ffd5b50505050505050505050565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b0381166118d0575030545b90565b60015f9081525f5160206153b65f395f51905f5260208190527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7548291906001600160a01b03165b6001600160a01b0381161580159061193d57506001600160a01b038116600114155b15611a48576040517ff551e2ee0000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063f551e2ee9061198f9033908c908c908c906004016146dd565b602060405180830381865afa1580156119aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ce9190614de4565b90507fffff00000000000000000000000000000000000000000000000000000000000081167f7739000000000000000000000000000000000000000000000000000000000000148015611a2d57506001600160e01b0319808516908216115b15611a36578093505b611a408383612d2f565b91505061191b565b50506001600160e01b0319811615611a605780611a6a565b6001600160e01b03195b95945050505050565b5f5f7f00000000000000000000000000000000000000000000000000000000000000009050306020526370a082315f526020806024601c845afa601f3d11166020510291505090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611b0557604051635629665f60e11b815260040160405180910390fd5b611b1260048484846123a7565b6004849091611b4657604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b50505f611b5d5f5160206153b65f395f51905f5290565b6001600160a01b0385165f908152600482016020526040812054919250819003611bdd576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527f2841d18703faaff388732165e48fe431468531b1b1e626b1b7cbcbfc0d79c74091015b60405180910390a1610e31565b611beb620151806003614d59565b611bf5908261522a565b4210611c4e576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527fcbd44a75f6935b5837022648b6c8487db984701200c5381c7c0f8c2b1d69b9da9101611bd0565b611c5b620151808261522a565b4210611cc5576001600160a01b0385165f908152600483016020526040812055611c86858585612cf2565b60408051600481526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e9101611bd0565b6040517f07f2f2d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81600881901b6001600160f81b031982161580611d2257506001600160f81b03198216600160f81b145b80611d3657506001600160f81b0319808316145b80156109a357506001600160f81b0319811615806109a357506001600160f81b03198116600160f81b146109a3565b6060611d83335f5160206153b65f395f51905f525b60010190612d82565b3390611dc7576040517fb927fe5e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f611de75f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b038116611e9557336002611e048282612dba565b86600881901b6001600160f81b03198216611e2b57611e24888883612e3c565b9550611e8c565b6001600160f81b03198216600160f81b03611e4b57611e24888883612f91565b6001600160f81b031980831603611e6757611e2488888361300a565b604051632e5bf3f960e21b81526001600160f81b0319831660048201526024016108b8565b50505050610ac9565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590611ec99033903490869036906004016146dd565b5f604051808303815f875af1158015611ee4573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611f0b91908101906147a5565b9050336002611f1a8282612dba565b87600881901b6001600160f81b03198216611f4157611f3a898983612e3c565b9650611f7d565b6001600160f81b03198216600160f81b03611f6157611f3a898983612f91565b6001600160f81b031980831603611e6757611f3a89898361300a565b5050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da9150611fad90849060040161484d565b5f604051808303815f87803b158015611fc4575f5ffd5b505af1158015611fd6573d5f5f3e3d5ffd5b5050505050509392505050565b6040517f35567e1a00000000000000000000000000000000000000000000000000000000815230600482015277ffffffffffffffffffffffffffffffffffffffffffffffff821660248201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906335567e1a90604401602060405180830381865afa158015612080573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611137919061505b565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146120ed57604051635629665f60e11b815260040160405180910390fd5b5f61210c5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166121845783600881901b6001600160f81b031982166121415761213c858583613158565b61217d565b6001600160f81b03198216600160f81b036121615761213c858583613224565b6001600160f81b031980831603611e675761213c858583613291565b50506110a4565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906121b89033903490869036906004016146dd565b5f604051808303815f875af11580156121d3573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526121fa91908101906147a5565b905084600881901b6001600160f81b031982166122215761221c868683613158565b61225d565b6001600160f81b03198216600160f81b036122415761221c868683613224565b6001600160f81b031980831603611e675761221c868683613291565b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061107590849060040161484d565b60605f6111227f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01858561276f565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806122ef57503330145b61230c57604051635629665f60e11b815260040160405180910390fd5b6110a484848484613335565b5f6001820361232957506001919050565b6002820361233957506001919050565b6003820361234957506001919050565b6004820361235957506001919050565b8161236657506001919050565b505f919050565b919050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f600185036123c0576123b984612466565b90506109a3565b600285036123d1576123b984613407565b6003850361244e575f600483106123ff576123ef60045f8587614d70565b6123f89161523d565b9050612402565b505f5b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409020546001600160a01b0385811691161490506109a3565b6004850361245f576123b98461341f565b505f6109a3565b5f6111375f5160206153b65f395f51905f5283612d82565b365f5f5f365f365f6124908a8a613458565b909e509c50949a509298509096509450925090506124bb6124b487878e88886134ac565b8383613541565b6124f1576040517f46fdc33300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6124fd8587868661289f565b505050505050935093915050565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f00000000000000000000000000000000000000000000000000000000000000004614166118d05750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a0902090565b5f5160206153b65f395f51905f526126377f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01613655565b610d4581613655565b5f600161265c815f5160206153b65f395f51905f525b90612d2f565b6001600160a01b03161415801561098e57505f61268760015f5160206153b65f395f51905f52612656565b6001600160a01b03161415905090565b7f00000000000000000000000000000000000000000000000000000000000000003081036126cc57639f03a0265f526004601cfd5b6126d5846136c9565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa5114612727576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a284905581156110a457604051828482375f388483885af4610e31573d5f823e3d81fd5b60605f61277d85858561371c565b90969095509350505050565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f000000000000000000000000000000000000000000000000000000000000000046141661287c5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b5f6128be5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b03811661296d576001600160a01b0384166128f557604051635316c18d60e01b815260040160405180910390fd5b60018503612908576116b28484846138dd565b6002850361291b576116b28484846139b6565b6003850361292e576116b2848484613a74565b60048503612941576116b2848484613dc8565b84612951576116b2848484613f1f565b6040516304c1896960e11b8152600481018690526024016108b8565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906129a19033903490869036906004016146dd565b5f604051808303815f875af11580156129bc573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526129e391908101906147a5565b90506001600160a01b038516612a0c57604051635316c18d60e01b815260040160405180910390fd5b60018603612a1f576117fd8585856138dd565b60028603612a32576117fd8585856139b6565b60038603612a45576117fd858585613a74565b60048603612a58576117fd858585613dc8565b85612a68576117fd858585613f1f565b6040516304c1896960e11b8152600481018790526024016108b8565b5f5160206153b65f395f51905f525f80612aa0858501866151aa565b9092509050612ab0838388614078565b612ab8612640565b612aee576040517fcc319d8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114ea5a5f5f638a91b0e360e01b85604051602401612b0d919061484d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038b169392919061414b565b5f80612b60838501856151aa565b91509150612b878286612b7d5f5160206153b65f395f51905f5290565b6001019190614078565b6113525a5f5f638a91b0e360e01b85604051602401612ba6919061484d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038a169392919061414b565b604080518082019091525f80825260208201525f5160206153b65f395f51905f526002015f612c1d6004828688614d70565b612c269161523d565b6001600160e01b03191681526020808201929092526040015f2082518154939092015160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199093166001600160a01b0390921691909117919091179055610e315a5f80638a91b0e360e01b612c9c866004818a614d70565b604051602401612cad929190615272565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b0388169392919061414b565b5f5160206153d65f395f51905f5280546001600160a01b0319169055610e315a5f5f638a91b0e360e01b8686604051602401612cad929190615272565b5f6001600160a01b038216612d6257604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b506001600160a01b039081165f9081526020929092526040909120541690565b5f60016001600160a01b03831614801590610acb5750506001600160a01b039081165f90815260209290925260409091205416151590565b5f546001600160a01b031680156114f0576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b158015612e2a575f5ffd5b505afa158015611352573d5f5f3e3d5ffd5b60605f5f365f612e4c88886141d1565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612e6b57509095505f90506001600160f81b03198716612ec157612e9f85858585614221565b865f81518110612eb157612eb1615285565b6020026020010181905250612f85565b6001600160f81b03198716600160f81b03612f6057612ee285858585614254565b875f81518110612ef457612ef4615285565b6020908102919091010152905080612f5b577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6628383885f81518110612f3b57612f3b615285565b6020026020010151604051612f5293929190615299565b60405180910390a15b612f85565b6040516308c3ee0360e11b81526001600160f81b0319881660048201526024016108b8565b50505050509392505050565b6060833584016020810190356001600160f81b03198416612fbd57612fb68282614282565b9250613001565b6001600160f81b03198416600160f81b03612fdc57612fb68282614358565b6040516308c3ee0360e11b81526001600160f81b0319851660048201526024016108b8565b50509392505050565b60605f365f613019878761448f565b6040805160018082528183019092529396509194509250816020015b606081526020019060019003908161303557509094505f90506001600160f81b0319861661308a576130688484846144c5565b855f8151811061307a5761307a615285565b602002602001018190525061314d565b6001600160f81b03198616600160f81b03613128576130aa8484846144f6565b865f815181106130bc576130bc615285565b6020908102919091010152905080613123577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c108383875f8151811061310357613103615285565b602002602001015160405161311a93929190615299565b60405180910390a15b61314d565b6040516308c3ee0360e11b81526001600160f81b0319871660048201526024016108b8565b505050509392505050565b5f5f365f61316687876141d1565b929650909450925090506001600160f81b031985166131905761318b84848484614522565b611352565b6001600160f81b03198516600160f81b036131ff575f5f6131b386868686614254565b91509150816131f8577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6628484836040516131ef93929190615299565b60405180910390a15b5050611352565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016108b8565b823583016020810190356001600160f81b03198316613247576116b28282614546565b6001600160f81b03198316600160f81b0361326c576132668282614358565b50610e31565b6040516308c3ee0360e11b81526001600160f81b0319841660048201526024016108b8565b5f365f61329e868661448f565b919450925090506001600160f81b031984166132c4576132bf8383836145a6565b61332d565b6001600160f81b03198416600160f81b03612fdc575f5f6132e68585856144f6565b91509150816114ea577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c1084848360405161332293929190615299565b60405180910390a150505b505050505050565b5f80546001600160a01b0319166001600160a01b038616908117909155156133ce576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e1906133a0908490879087906004016152be565b5f604051808303815f87803b1580156133b7575f5ffd5b505af11580156133c9573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b5f611137825f5160206153b65f395f51905f52611d7a565b5f816001600160a01b03166134485f5160206153d65f395f51905f52546001600160a01b031690565b6001600160a01b03161492915050565b813560601c6014830135603880850190603486013560e090811c91603c838901818101939281013590921c9136915f9184018b90030161349a8a82818e614d70565b92509250509295985092959890939650565b5f6040518060800160405280605b81526020016153f6605b91398051906020012086868686866040516134e09291906151f7565b60405190819003812061352095949392916020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b60405160208183030381529060405280519060200120905095945050505050565b5f806135506014828587614d70565b61355991614d97565b60601c905061356781612466565b61358f5760405163342cf00f60e11b81526001600160a01b03821660048201526024016108b8565b5f61359986612789565b90506001600160a01b03821663f551e2ee30836135b9886014818c614d70565b6040518563ffffffff1660e01b81526004016135d894939291906146dd565b602060405180830381865afa925050508015613611575060408051601f3d908101601f1916820190925261360e91810190614de4565b60015b61361f575f92505050610acb565b6001600160e01b0319167f1626ba7e00000000000000000000000000000000000000000000000000000000149250610acb915050565b60015f908152602082905260409020546001600160a01b0316156136a5576040517f53c85e6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806136ff57503330145b610d4557604051635629665f60e11b815260040160405180910390fd5b60605f6001600160a01b038416600114801590613740575061373e8585612d82565b155b1561376957604051637c84ecfb60e01b81526001600160a01b03851660048201526024016108b8565b825f036137a2576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff8111156137bb576137bb61470f565b6040519080825280602002602001820160405280156137e4578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061382857506001600160a01b038216600114155b801561383357508381105b1561388c578183828151811061384b5761384b615285565b6001600160a01b039283166020918202929092018101919091529281165f90815292879052604090922054909116908061388481615315565b915050613806565b6001600160a01b0382166001148015906138a557505f81115b156138d157826138b660018361532d565b815181106138c6576138c6615285565b602002602001015191505b80835250935093915050565b8260016138ea8282612dba565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa15801561392d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139519190615340565b613971576040516369c9a24560e11b8152600160048201526024016108b8565b6139885f5160206153b65f395f51905f52866145c8565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe70906110759087908790600401615272565b8260026139c38282612dba565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613a06573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a2a9190615340565b613a4a576040516369c9a24560e11b8152600260048201526024016108b8565b6139887f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01866145c8565b826003613a818282612dba565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613ac4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ae89190615340565b613b08576040516369c9a24560e11b8152600360048201526024016108b8565b5f613b166004828688614d70565b613b1f9161523d565b90505f85856004818110613b3557613b35615285565b909101356001600160f81b031916915050801580613b6057506001600160f81b03198116607f60f91b145b613b96576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613ba4866005818a614d70565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b1480613c0957506001600160e01b03198316638a91b0e360e01b145b80613c1c57506001600160e01b03198316155b15613c53576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b031615613cda576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199092169316929092179190911790915590516306d61fe760e41b8152636d61fe7090613d9190849060040161484d565b5f604051808303815f87803b158015613da8575f5ffd5b505af1158015613dba573d5f5f3e3d5ffd5b505050505050505050505050565b826004613dd58282612dba565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613e17573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e3b9190615340565b613e5a576040516369c9a24560e11b81526004818101526024016108b8565b5f613e795f5160206153d65f395f51905f52546001600160a01b031690565b9050806001600160a01b03811615613ec9576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f5160206153d65f395f51905f5280546001600160a01b0319166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe70906118679088908890600401615272565b813582016020818101913590848101358501908101903582818114613f70576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b8181101561109e575f868683818110613f8d57613f8d615285565b90506020020135905060018103613fd057613fcb8a868685818110613fb457613fb4615285565b9050602002810190613fc69190614f4c565b6138dd565b61406f565b6002810361400557613fcb8a868685818110613fee57613fee615285565b90506020028101906140009190614f4c565b6139b6565b6003810361403a57613fcb8a86868581811061402357614023615285565b90506020028101906140359190614f4c565b613a74565b6004810361406f5761406f8a86868581811061405857614058615285565b905060200281019061406a9190614f4c565b613dc8565b50600101613f72565b6001600160a01b038116158061409757506001600160a01b0381166001145b156140c057604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b6001600160a01b038281165f9081526020859052604090205481169082161461410757604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b039081165f8181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b5f60605f5f5f8661ffff1667ffffffffffffffff81111561416e5761416e61470f565b6040519080825280601f01601f191660200182016040528015614198576020820181803683370190505b5090505f5f8751602089018b8e8ef191503d9250868311156141b8578692505b828152825f602083013e90999098509650505050505050565b5f8036816141e26014828789614d70565b6141eb91614d97565b60601c93506141fe603460148789614d70565b6142079161535f565b92506142168560348189614d70565b949793965094505050565b604051818382375f38838387895af161423c573d5f823e3d81fd5b3d8152602081013d5f823e3d01604052949350505050565b6040515f90828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b60608167ffffffffffffffff81111561429d5761429d61470f565b6040519080825280602002602001820160405280156142d057816020015b60608152602001906001900390816142bb5790505b509050365f5b83811015614350578484828181106142f0576142f0615285565b9050602002810190614302919061537c565b915061432b614314602084018461539a565b60208401356143266040860186614f4c565b614221565b83828151811061433d5761433d615285565b60209081029190910101526001016142d6565b505092915050565b60608167ffffffffffffffff8111156143735761437361470f565b6040519080825280602002602001820160405280156143a657816020015b60608152602001906001900390816143915790505b509050365f5b83811015614350578484828181106143c6576143c6615285565b90506020028101906143d8919061537c565b91505f6144026143eb602085018561539a565b60208501356143fd6040870187614f4c565b614254565b85848151811061441457614414615285565b6020908102919091010152905080614486577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6626144546040850185614f4c565b86858151811061446657614466615285565b602002602001015160405161447d93929190615299565b60405180910390a15b506001016143ac565b5f368161449f6014828688614d70565b6144a891614d97565b60601c92506144ba8460148188614d70565b915091509250925092565b604051818382375f388383875af46144df573d5f823e3d81fd5b3d8152602081013d5f823e3d016040529392505050565b6040515f90828482375f388483885af491503d8152602081013d5f823e3d810160405250935093915050565b604051818382375f38838387895af161453d573d5f823e3d81fd5b01604052505050565b365f5b828110156110a45783838281811061456357614563615285565b9050602002810190614575919061537c565b915061459e614587602084018461539a565b60208401356145996040860186614f4c565b614522565b600101614549565b604051818382375f388383875af46145c0573d5f823e3d81fd5b016040525050565b6001600160a01b03811615806145e757506001600160a01b0381166001145b1561461057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b038181165f90815260208490526040902054161561466c576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108b8565b60015f818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6147056060830184866146b5565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051610120810167ffffffffffffffff811182821017156147475761474761470f565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156147765761477661470f565b604052919050565b5f67ffffffffffffffff8211156147975761479761470f565b50601f01601f191660200190565b5f602082840312156147b5575f5ffd5b815167ffffffffffffffff8111156147cb575f5ffd5b8201601f810184136147db575f5ffd5b80516147ee6147e98261477e565b61474d565b818152856020838501011115614802575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610acb602083018461481f565b6001600160a01b0381168114610d45575f5ffd5b803561236d8161485f565b5f5f83601f84011261488e575f5ffd5b50813567ffffffffffffffff8111156148a5575f5ffd5b6020830191508360208285010111156148bc575f5ffd5b9250929050565b5f5f5f5f606085870312156148d6575f5ffd5b8435935060208501356148e88161485f565b9250604085013567ffffffffffffffff811115614903575f5ffd5b61490f8782880161487e565b95989497509550505050565b5f5f5f6040848603121561492d575f5ffd5b83359250602084013567ffffffffffffffff81111561494a575f5ffd5b6149568682870161487e565b9497909650939450505050565b5f6101208284031215614974575f5ffd5b50919050565b5f5f5f6060848603121561498c575f5ffd5b833567ffffffffffffffff8111156149a2575f5ffd5b6149ae86828701614963565b9660208601359650604090950135949350505050565b6001600160e01b031981168114610d45575f5ffd5b5f602082840312156149e9575f5ffd5b8135610acb816149c4565b5f5f60208385031215614a05575f5ffd5b823567ffffffffffffffff811115614a1b575f5ffd5b61277d8582860161487e565b5f5f60408385031215614a38575f5ffd5b8235614a438161485f565b946020939093013593505050565b5f5f5f60408486031215614a63575f5ffd5b8335614a6e8161485f565b9250602084013567ffffffffffffffff81111561494a575f5ffd5b604080825283519082018190525f9060208501906060840190835b81811015614acb5783516001600160a01b0316835260209384019390920191600101614aa4565b505080925050506001600160a01b03831660208301529392505050565b5f60208284031215614af8575f5ffd5b5035919050565b6001600160f81b03198816815260e060208201525f614b2160e083018961481f565b8281036040840152614b33818961481f565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614b88578351835260209384019390920191600101614b6a565b50909b9a5050505050505050505050565b5f5f60408385031215614baa575f5ffd5b823567ffffffffffffffff811115614bc0575f5ffd5b614bcc85828601614963565b95602094909401359450505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015614c3257603f19878603018452614c1d85835161481f565b94506020938401939190910190600101614c01565b50929695505050505050565b5f60208284031215614c4e575f5ffd5b813577ffffffffffffffffffffffffffffffffffffffffffffffff81168114610acb575f5ffd5b5f5f5f5f60608587031215614c88575f5ffd5b8435614c938161485f565b9350602085013567ffffffffffffffff811115614cae575f5ffd5b8501601f81018713614cbe575f5ffd5b803567ffffffffffffffff811115614cd4575f5ffd5b8760208260051b8401011115614ce8575f5ffd5b60209190910193509150604085013560ff81168114614d05575f5ffd5b939692955090935050565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52601160045260245ffd5b5f82614d5457634e487b7160e01b5f52601260045260245ffd5b500490565b808202811582820484141761113757611137614d26565b5f5f85851115614d7e575f5ffd5b83861115614d8a575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff198116906014841015614ddd576bffffffffffffffffffffffff196bffffffffffffffffffffffff198560140360031b1b82161691505b5092915050565b5f60208284031215614df4575f5ffd5b8151610acb816149c4565b5f82601f830112614e0e575f5ffd5b8135614e1c6147e98261477e565b818152846020838601011115614e30575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f6101208236031215614e5d575f5ffd5b614e65614723565b614e6e83614873565b815260208381013590820152604083013567ffffffffffffffff811115614e93575f5ffd5b614e9f36828601614dff565b604083015250606083013567ffffffffffffffff811115614ebe575f5ffd5b614eca36828601614dff565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e083013567ffffffffffffffff811115614f07575f5ffd5b614f1336828601614dff565b60e08301525061010083013567ffffffffffffffff811115614f33575f5ffd5b614f3f36828601614dff565b6101008301525092915050565b5f5f8335601e19843603018112614f61575f5ffd5b83018035915067ffffffffffffffff821115614f7b575f5ffd5b6020019150368190038213156148bc575f5ffd5b60408152614fa96040820184516001600160a01b03169052565b602083015160608201525f60408401516101206080840152614fcf61016084018261481f565b90506060850151603f198483030160a0850152614fec828261481f565b915050608085015160c084015260a085015160e084015260c085015161010084015260e0850151603f198483030161012085015261502a828261481f565b915050610100850151603f198483030161014085015261504a828261481f565b925050508260208301529392505050565b5f6020828403121561506b575f5ffd5b5051919050565b5f5f8335601e19843603018112615087575f5ffd5b830160208101925035905067ffffffffffffffff8111156150a6575f5ffd5b8036038213156148bc575f5ffd5b6150ce826150c183614873565b6001600160a01b03169052565b602081810135908301525f6150e66040830183615072565b61012060408601526150fd610120860182846146b5565b91505061510d6060840184615072565b85830360608701526151208382846146b5565b6080868101359088015260a0808701359088015260c08087013590880152925061515091505060e0840184615072565b85830360e08701526151638382846146b5565b92505050615175610100840184615072565b8583036101008701526147058382846146b5565b604081525f61519b60408301856150b4565b90508260208301529392505050565b5f5f604083850312156151bb575f5ffd5b82356151c68161485f565b9150602083013567ffffffffffffffff8111156151e1575f5ffd5b6151ed85828601614dff565b9150509250929050565b818382375f9101908152919050565b604081525f61521860408301856150b4565b8281036020840152611a6a818561481f565b8082018082111561113757611137614d26565b80356001600160e01b03198116906004841015614ddd576001600160e01b0319808560040360031b1b82161691505092915050565b602081525f6109a36020830184866146b5565b634e487b7160e01b5f52603260045260245ffd5b604081525f6152ac6040830185876146b5565b8281036020840152614705818561481f565b60ff8416815260406020820181905281018290525f8360608301825b8581101561530a5782356152ed8161485f565b6001600160a01b03168252602092830192909101906001016152da565b509695505050505050565b5f6001820161532657615326614d26565b5060010190565b8181038181111561113757611137614d26565b5f60208284031215615350575f5ffd5b81518015158114610acb575f5ffd5b80356020831015611137575f19602084900360031b1b1692915050565b5f8235605e19833603018112615390575f5ffd5b9190910192915050565b5f602082840312156153aa575f5ffd5b8135610acb8161485f56fe0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f034d6f64756c65456e61626c654d6f64652861646472657373206d6f64756c652c75696e74323536206d6f64756c65547970652c6279746573333220757365724f70486173682c6279746573333220696e6974446174614861736829a164736f6c634300081b000a0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Deployed Bytecode
0x6080604052600436106101db575f3560e01c80638dd7712f11610101578063cd64f80a11610094578063e9ae5c5311610063578063e9ae5c53146106f2578063ea5f61d014610705578063eab77e1714610724578063f2dc691d14610737576101e2565b8063cd64f80a14610681578063d03c791414610694578063d691c964146106b3578063d86f2b3c146106d3576101e2565b8063aaf10f42116100d0578063aaf10f4214610608578063b0d691fe1461061c578063b46b61a91461064e578063c399ec881461066d576101e2565b80638dd7712f146105845780639517e29f146105975780639cfd7cff146105aa578063a71763a8146105f5576101e2565b80634b6a1419116101795780635faac46b116101485780635faac46b146104f35780636575f6aa146105205780637b1039991461053f57806384b0196e1461055d576101e2565b80634b6a1419146104a65780634d44560d146104b95780634f1ef286146104cc57806352d1902d146104df576101e2565b806319822f7c116101b557806319822f7c146103a95780633644e515146103d6578063481ddd23146103ea5780634a58db191461049c576101e2565b80630a664dba14610311578063112d3a7d146103425780631626ba7e14610371576101e2565b366101e257005b5f3660605f6102055f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166102265761021f8484610756565b9150610305565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061025a9033903490869036906004016146dd565b5f604051808303815f875af1158015610275573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261029c91908101906147a5565b90506102a88585610756565b9250604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906102d690849060040161484d565b5f604051808303815f87803b1580156102ed575f5ffd5b505af11580156102ff573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b34801561031c575f5ffd5b5061032561096f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561034d575f5ffd5b5061036161035c3660046148c3565b610993565b6040519015158152602001610339565b34801561037c575f5ffd5b5061039061038b36600461491b565b6109ab565b6040516001600160e01b03199091168152602001610339565b3480156103b4575f5ffd5b506103c86103c336600461497a565b610ad2565b604051908152602001610339565b3480156103e1575f5ffd5b506103c8610d0b565b3480156103f5575f5ffd5b506104746104043660046149d9565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b03909116602083015201610339565b6104a4610d14565b005b6104a46104b43660046149f4565b610d48565b6104a46104c7366004614a27565b610e38565b6104a46104da366004614a51565b610eed565b3480156104ea575f5ffd5b506103c86110aa565b3480156104fe575f5ffd5b5061051261050d366004614a27565b611107565b604051610339929190614a89565b34801561052b575f5ffd5b506103c861053a366004614ae8565b61112d565b34801561054a575f5ffd5b505f54610325906001600160a01b031681565b348015610568575f5ffd5b5061057161113d565b6040516103399796959493929190614aff565b6104a4610592366004614b99565b6111e5565b6104a46105a53660046148c3565b6114f5565b3480156105b5575f5ffd5b50604080518082018252601481527f6269636f6e6f6d792e6e657875732e312e302e3000000000000000000000000060208201529051610339919061484d565b6104a46106033660046148c3565b61159b565b348015610613575f5ffd5b5061032561189c565b348015610627575f5ffd5b507f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032610325565b348015610659575f5ffd5b5061039061066836600461491b565b6118d3565b348015610678575f5ffd5b506103c8611a73565b6104a461068f366004614a51565b611abc565b34801561069f575f5ffd5b506103616106ae366004614ae8565b611cf7565b6106c66106c136600461491b565b611d65565b6040516103399190614bdb565b3480156106de575f5ffd5b506103c86106ed366004614c3e565b611fe3565b6104a461070036600461491b565b6120a4565b348015610710575f5ffd5b5061051261071f366004614a27565b61228b565b6104a4610732366004614c75565b6122b9565b348015610742575f5ffd5b50610361610751366004614ae8565b612318565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b81156108d3576001600160f81b03198116607f60f91b0361082c57816001600160a01b03166107d88888612372565b6040516107e59190614d10565b5f60405180830381855afa9150503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b606091505b50955093506108c1565b6001600160f81b0319811661089757816001600160a01b0316346108508989612372565b60405161085d9190614d10565b5f6040518083038185875af1925050503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b604051632e5bf3f960e21b81526001600160f81b0319821660048201526024015b60405180910390fd5b836108ce57845160208601fd5b610965565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561091257600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f351685610962576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b50505b5050505092915050565b5f61098e5f5160206153d65f395f51905f52546001600160a01b031690565b905090565b5f6109a0858585856123a7565b90505b949350505050565b5f8181036109e4576109c061ffff8319614d3a565b6109cc90617739614d59565b84036109e4576109dd8484846118d3565b9050610acb565b5f6109f26014828587614d70565b6109fb91614d97565b60601c9050610a0981612466565b8190610a345760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b506001600160a01b03811663f551e2ee3387610a53876014818b614d70565b6040518563ffffffff1660e01b8152600401610a7294939291906146dd565b602060405180830381865afa925050508015610aab575060408051601f3d908101601f19168201909252610aa891810190614de4565b60015b610ac057506001600160e01b03199050610acb565b9150610acb9050565b505b9392505050565b5f81336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321614610b1d57604051635629665f60e11b815260040160405180910390fd5b5f602086013560401c6001600160a01b03169050600160f81b602087013560031a60f81b03610c4d575f610b5087614e4c565b9050610b6986610b646101008a018a614f4c565b61247e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505050610100820152610bab82612466565b8290610bd65760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b50604051639700320360e01b81526001600160a01b03831690639700320390610c059084908a90600401614f8f565b6020604051808303815f875af1158015610c21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c45919061505b565b935050610cf3565b610c5681612466565b8190610c815760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b50604051639700320360e01b81526001600160a01b03821690639700320390610cb09089908990600401615189565b6020604051808303815f875af1158015610ccc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf0919061505b565b92505b508015610ac9575f385f3884335af150509392505050565b5f61098e61250b565b7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0325f38818134855af1610d45575f38fd5b50565b610d50612600565b5f80610d5e838501856151aa565b915091505f826001600160a01b031682604051610d7b9190614d10565b5f60405180830381855af49150503d805f8114610db3576040519150601f19603f3d011682016040523d82523d5f602084013e610db8565b606091505b5050905080610df3576040517f315927c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dfb612640565b610e31576040517fc4d0a0b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032161480610e6e57503330145b610e8b57604051635629665f60e11b815260040160405180910390fd5b5f7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032905060405183601452826034526f205c28780000000000000000000000005f525f38604460105f865af1610ee3573d5f823e3d81fd5b505f603452505050565b5f610f0c5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b038116610f79576001600160a01b038416610f435760405163325c055b60e21b815260040160405180910390fd5b833b151580610f655760405163325c055b60e21b815260040160405180910390fd5b843055610f73858585612697565b506110a4565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590610fad9033903490869036906004016146dd565b5f604051808303815f875af1158015610fc8573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610fef91908101906147a5565b90506001600160a01b0385166110185760405163325c055b60e21b815260040160405180910390fd5b843b15158061103a5760405163325c055b60e21b815260040160405180910390fd5b853055611048868686612697565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061107590849060040161484d565b5f604051808303815f87803b15801561108c575f5ffd5b505af115801561109e573d5f5f3e3d5ffd5b50505050505b50505050565b5f7f0000000000000000000000006fe0f7451f69fdd67e21390b2935ccbbb42fc99e3081146110e057639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b60605f6111225f5160206153b65f395f51905f52858561276f565b909590945092505050565b5f61113782612789565b92915050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f8080836111d360408051808201825260058082527f4e6578757300000000000000000000000000000000000000000000000000000060208084019190915283518085019094529083527f312e302e310000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032161461122e57604051635629665f60e11b815260040160405180910390fd5b5f61124d5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b03811661135b57365f61126c6060860186614f4c565b61127a916004908290614d70565b915091505f5f306001600160a01b0316848460405161129a9291906151f7565b5f60405180830381855af49150503d805f81146112d2576040519150601f19603f3d011682016040523d82523d5f602084013e6112d7565b606091505b50915091508115611320577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f8782604051611313929190615206565b60405180910390a1611352565b6040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061138f9033903490869036906004016146dd565b5f604051808303815f875af11580156113aa573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113d191908101906147a5565b9050365f6113e26060870187614f4c565b6113f0916004908290614d70565b915091505f5f306001600160a01b031684846040516114109291906151f7565b5f60405180830381855af49150503d805f8114611448576040519150601f19603f3d011682016040523d82523d5f602084013e61144d565b606091505b50915091508115611320577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f8882604051611489929190615206565b60405180910390a15050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da91506114c190849060040161484d565b5f604051808303815f87803b1580156114d8575f5ffd5b505af11580156114ea573d5f5f3e3d5ffd5b50505050505b505050565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03216148061152b57503330145b61154857604051635629665f60e11b815260040160405180910390fd5b6115548484848461289f565b604080518581526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123910160405180910390a150505050565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321614806115d157503330145b6115ee57604051635629665f60e11b815260040160405180910390fd5b5f61160d5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166116f057611629858585856123a7565b8585909161165c57604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518681526001600160a01b03861660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a1600185036116b7576116b2848484612a84565b610e31565b600285036116ca576116b2848484612b52565b600385036116dd576116b2848484612beb565b600485036116b2576116b2848484612cf2565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906117249033903490869036906004016146dd565b5f604051808303815f875af115801561173f573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261176691908101906147a5565b9050611774868686866123a7565b868690916117a757604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a160018603611802576117fd858585612a84565b61183b565b60028603611815576117fd858585612b52565b60038603611828576117fd858585612beb565b6004860361183b5761183b858585612cf2565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061186790849060040161484d565b5f604051808303815f87803b15801561187e575f5ffd5b505af1158015611890573d5f5f3e3d5ffd5b50505050505050505050565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b0381166118d0575030545b90565b60015f9081525f5160206153b65f395f51905f5260208190527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7548291906001600160a01b03165b6001600160a01b0381161580159061193d57506001600160a01b038116600114155b15611a48576040517ff551e2ee0000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063f551e2ee9061198f9033908c908c908c906004016146dd565b602060405180830381865afa1580156119aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ce9190614de4565b90507fffff00000000000000000000000000000000000000000000000000000000000081167f7739000000000000000000000000000000000000000000000000000000000000148015611a2d57506001600160e01b0319808516908216115b15611a36578093505b611a408383612d2f565b91505061191b565b50506001600160e01b0319811615611a605780611a6a565b6001600160e01b03195b95945050505050565b5f5f7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0329050306020526370a082315f526020806024601c845afa601f3d11166020510291505090565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321614611b0557604051635629665f60e11b815260040160405180910390fd5b611b1260048484846123a7565b6004849091611b4657604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b50505f611b5d5f5160206153b65f395f51905f5290565b6001600160a01b0385165f908152600482016020526040812054919250819003611bdd576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527f2841d18703faaff388732165e48fe431468531b1b1e626b1b7cbcbfc0d79c74091015b60405180910390a1610e31565b611beb620151806003614d59565b611bf5908261522a565b4210611c4e576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527fcbd44a75f6935b5837022648b6c8487db984701200c5381c7c0f8c2b1d69b9da9101611bd0565b611c5b620151808261522a565b4210611cc5576001600160a01b0385165f908152600483016020526040812055611c86858585612cf2565b60408051600481526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e9101611bd0565b6040517f07f2f2d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81600881901b6001600160f81b031982161580611d2257506001600160f81b03198216600160f81b145b80611d3657506001600160f81b0319808316145b80156109a357506001600160f81b0319811615806109a357506001600160f81b03198116600160f81b146109a3565b6060611d83335f5160206153b65f395f51905f525b60010190612d82565b3390611dc7576040517fb927fe5e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f611de75f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b038116611e9557336002611e048282612dba565b86600881901b6001600160f81b03198216611e2b57611e24888883612e3c565b9550611e8c565b6001600160f81b03198216600160f81b03611e4b57611e24888883612f91565b6001600160f81b031980831603611e6757611e2488888361300a565b604051632e5bf3f960e21b81526001600160f81b0319831660048201526024016108b8565b50505050610ac9565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590611ec99033903490869036906004016146dd565b5f604051808303815f875af1158015611ee4573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611f0b91908101906147a5565b9050336002611f1a8282612dba565b87600881901b6001600160f81b03198216611f4157611f3a898983612e3c565b9650611f7d565b6001600160f81b03198216600160f81b03611f6157611f3a898983612f91565b6001600160f81b031980831603611e6757611f3a89898361300a565b5050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da9150611fad90849060040161484d565b5f604051808303815f87803b158015611fc4575f5ffd5b505af1158015611fd6573d5f5f3e3d5ffd5b5050505050509392505050565b6040517f35567e1a00000000000000000000000000000000000000000000000000000000815230600482015277ffffffffffffffffffffffffffffffffffffffffffffffff821660248201525f907f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316906335567e1a90604401602060405180830381865afa158015612080573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611137919061505b565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03216146120ed57604051635629665f60e11b815260040160405180910390fd5b5f61210c5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166121845783600881901b6001600160f81b031982166121415761213c858583613158565b61217d565b6001600160f81b03198216600160f81b036121615761213c858583613224565b6001600160f81b031980831603611e675761213c858583613291565b50506110a4565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906121b89033903490869036906004016146dd565b5f604051808303815f875af11580156121d3573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526121fa91908101906147a5565b905084600881901b6001600160f81b031982166122215761221c868683613158565b61225d565b6001600160f81b03198216600160f81b036122415761221c868683613224565b6001600160f81b031980831603611e675761221c868683613291565b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061107590849060040161484d565b60605f6111227f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01858561276f565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321614806122ef57503330145b61230c57604051635629665f60e11b815260040160405180910390fd5b6110a484848484613335565b5f6001820361232957506001919050565b6002820361233957506001919050565b6003820361234957506001919050565b6004820361235957506001919050565b8161236657506001919050565b505f919050565b919050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f600185036123c0576123b984612466565b90506109a3565b600285036123d1576123b984613407565b6003850361244e575f600483106123ff576123ef60045f8587614d70565b6123f89161523d565b9050612402565b505f5b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409020546001600160a01b0385811691161490506109a3565b6004850361245f576123b98461341f565b505f6109a3565b5f6111375f5160206153b65f395f51905f5283612d82565b365f5f5f365f365f6124908a8a613458565b909e509c50949a509298509096509450925090506124bb6124b487878e88886134ac565b8383613541565b6124f1576040517f46fdc33300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6124fd8587868661289f565b505050505050935093915050565b7f51bf3f38d8a041fe84f0eb532e5abb888e2dd7582220c2bca051a9f02ff956077f0000000000000000000000006fe0f7451f69fdd67e21390b2935ccbbb42fc99e30147f000000000000000000000000000000000000000000000000000000000000dede4614166118d05750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527ff3fbaf4e62ef217b8151b366cdaba8fa578e78940637d6c1ec320d10a718877260208201527ffc7f6d936935ae6385924f29da7af79e941070dafe46831a51595892abc1b97a9181019190915246606082015230608082015260a0902090565b5f5160206153b65f395f51905f526126377f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01613655565b610d4581613655565b5f600161265c815f5160206153b65f395f51905f525b90612d2f565b6001600160a01b03161415801561098e57505f61268760015f5160206153b65f395f51905f52612656565b6001600160a01b03161415905090565b7f0000000000000000000000006fe0f7451f69fdd67e21390b2935ccbbb42fc99e3081036126cc57639f03a0265f526004601cfd5b6126d5846136c9565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa5114612727576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a284905581156110a457604051828482375f388483885af4610e31573d5f823e3d81fd5b60605f61277d85858561371c565b90969095509350505050565b7f51bf3f38d8a041fe84f0eb532e5abb888e2dd7582220c2bca051a9f02ff956077f0000000000000000000000006fe0f7451f69fdd67e21390b2935ccbbb42fc99e30147f000000000000000000000000000000000000000000000000000000000000dede46141661287c5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527ff3fbaf4e62ef217b8151b366cdaba8fa578e78940637d6c1ec320d10a718877260208201527ffc7f6d936935ae6385924f29da7af79e941070dafe46831a51595892abc1b97a9181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b5f6128be5f5160206153d65f395f51905f52546001600160a01b031690565b90506001600160a01b03811661296d576001600160a01b0384166128f557604051635316c18d60e01b815260040160405180910390fd5b60018503612908576116b28484846138dd565b6002850361291b576116b28484846139b6565b6003850361292e576116b2848484613a74565b60048503612941576116b2848484613dc8565b84612951576116b2848484613f1f565b6040516304c1896960e11b8152600481018690526024016108b8565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906129a19033903490869036906004016146dd565b5f604051808303815f875af11580156129bc573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526129e391908101906147a5565b90506001600160a01b038516612a0c57604051635316c18d60e01b815260040160405180910390fd5b60018603612a1f576117fd8585856138dd565b60028603612a32576117fd8585856139b6565b60038603612a45576117fd858585613a74565b60048603612a58576117fd858585613dc8565b85612a68576117fd858585613f1f565b6040516304c1896960e11b8152600481018790526024016108b8565b5f5160206153b65f395f51905f525f80612aa0858501866151aa565b9092509050612ab0838388614078565b612ab8612640565b612aee576040517fcc319d8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114ea5a5f5f638a91b0e360e01b85604051602401612b0d919061484d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038b169392919061414b565b5f80612b60838501856151aa565b91509150612b878286612b7d5f5160206153b65f395f51905f5290565b6001019190614078565b6113525a5f5f638a91b0e360e01b85604051602401612ba6919061484d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038a169392919061414b565b604080518082019091525f80825260208201525f5160206153b65f395f51905f526002015f612c1d6004828688614d70565b612c269161523d565b6001600160e01b03191681526020808201929092526040015f2082518154939092015160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199093166001600160a01b0390921691909117919091179055610e315a5f80638a91b0e360e01b612c9c866004818a614d70565b604051602401612cad929190615272565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b0388169392919061414b565b5f5160206153d65f395f51905f5280546001600160a01b0319169055610e315a5f5f638a91b0e360e01b8686604051602401612cad929190615272565b5f6001600160a01b038216612d6257604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b506001600160a01b039081165f9081526020929092526040909120541690565b5f60016001600160a01b03831614801590610acb5750506001600160a01b039081165f90815260209290925260409091205416151590565b5f546001600160a01b031680156114f0576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b158015612e2a575f5ffd5b505afa158015611352573d5f5f3e3d5ffd5b60605f5f365f612e4c88886141d1565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612e6b57509095505f90506001600160f81b03198716612ec157612e9f85858585614221565b865f81518110612eb157612eb1615285565b6020026020010181905250612f85565b6001600160f81b03198716600160f81b03612f6057612ee285858585614254565b875f81518110612ef457612ef4615285565b6020908102919091010152905080612f5b577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6628383885f81518110612f3b57612f3b615285565b6020026020010151604051612f5293929190615299565b60405180910390a15b612f85565b6040516308c3ee0360e11b81526001600160f81b0319881660048201526024016108b8565b50505050509392505050565b6060833584016020810190356001600160f81b03198416612fbd57612fb68282614282565b9250613001565b6001600160f81b03198416600160f81b03612fdc57612fb68282614358565b6040516308c3ee0360e11b81526001600160f81b0319851660048201526024016108b8565b50509392505050565b60605f365f613019878761448f565b6040805160018082528183019092529396509194509250816020015b606081526020019060019003908161303557509094505f90506001600160f81b0319861661308a576130688484846144c5565b855f8151811061307a5761307a615285565b602002602001018190525061314d565b6001600160f81b03198616600160f81b03613128576130aa8484846144f6565b865f815181106130bc576130bc615285565b6020908102919091010152905080613123577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c108383875f8151811061310357613103615285565b602002602001015160405161311a93929190615299565b60405180910390a15b61314d565b6040516308c3ee0360e11b81526001600160f81b0319871660048201526024016108b8565b505050509392505050565b5f5f365f61316687876141d1565b929650909450925090506001600160f81b031985166131905761318b84848484614522565b611352565b6001600160f81b03198516600160f81b036131ff575f5f6131b386868686614254565b91509150816131f8577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6628484836040516131ef93929190615299565b60405180910390a15b5050611352565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016108b8565b823583016020810190356001600160f81b03198316613247576116b28282614546565b6001600160f81b03198316600160f81b0361326c576132668282614358565b50610e31565b6040516308c3ee0360e11b81526001600160f81b0319841660048201526024016108b8565b5f365f61329e868661448f565b919450925090506001600160f81b031984166132c4576132bf8383836145a6565b61332d565b6001600160f81b03198416600160f81b03612fdc575f5f6132e68585856144f6565b91509150816114ea577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c1084848360405161332293929190615299565b60405180910390a150505b505050505050565b5f80546001600160a01b0319166001600160a01b038616908117909155156133ce576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e1906133a0908490879087906004016152be565b5f604051808303815f87803b1580156133b7575f5ffd5b505af11580156133c9573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b5f611137825f5160206153b65f395f51905f52611d7a565b5f816001600160a01b03166134485f5160206153d65f395f51905f52546001600160a01b031690565b6001600160a01b03161492915050565b813560601c6014830135603880850190603486013560e090811c91603c838901818101939281013590921c9136915f9184018b90030161349a8a82818e614d70565b92509250509295985092959890939650565b5f6040518060800160405280605b81526020016153f6605b91398051906020012086868686866040516134e09291906151f7565b60405190819003812061352095949392916020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b60405160208183030381529060405280519060200120905095945050505050565b5f806135506014828587614d70565b61355991614d97565b60601c905061356781612466565b61358f5760405163342cf00f60e11b81526001600160a01b03821660048201526024016108b8565b5f61359986612789565b90506001600160a01b03821663f551e2ee30836135b9886014818c614d70565b6040518563ffffffff1660e01b81526004016135d894939291906146dd565b602060405180830381865afa925050508015613611575060408051601f3d908101601f1916820190925261360e91810190614de4565b60015b61361f575f92505050610acb565b6001600160e01b0319167f1626ba7e00000000000000000000000000000000000000000000000000000000149250610acb915050565b60015f908152602082905260409020546001600160a01b0316156136a5576040517f53c85e6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b336001600160a01b037f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321614806136ff57503330145b610d4557604051635629665f60e11b815260040160405180910390fd5b60605f6001600160a01b038416600114801590613740575061373e8585612d82565b155b1561376957604051637c84ecfb60e01b81526001600160a01b03851660048201526024016108b8565b825f036137a2576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff8111156137bb576137bb61470f565b6040519080825280602002602001820160405280156137e4578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061382857506001600160a01b038216600114155b801561383357508381105b1561388c578183828151811061384b5761384b615285565b6001600160a01b039283166020918202929092018101919091529281165f90815292879052604090922054909116908061388481615315565b915050613806565b6001600160a01b0382166001148015906138a557505f81115b156138d157826138b660018361532d565b815181106138c6576138c6615285565b602002602001015191505b80835250935093915050565b8260016138ea8282612dba565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa15801561392d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139519190615340565b613971576040516369c9a24560e11b8152600160048201526024016108b8565b6139885f5160206153b65f395f51905f52866145c8565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe70906110759087908790600401615272565b8260026139c38282612dba565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613a06573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a2a9190615340565b613a4a576040516369c9a24560e11b8152600260048201526024016108b8565b6139887f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01866145c8565b826003613a818282612dba565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613ac4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ae89190615340565b613b08576040516369c9a24560e11b8152600360048201526024016108b8565b5f613b166004828688614d70565b613b1f9161523d565b90505f85856004818110613b3557613b35615285565b909101356001600160f81b031916915050801580613b6057506001600160f81b03198116607f60f91b145b613b96576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613ba4866005818a614d70565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b1480613c0957506001600160e01b03198316638a91b0e360e01b145b80613c1c57506001600160e01b03198316155b15613c53576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b031615613cda576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199092169316929092179190911790915590516306d61fe760e41b8152636d61fe7090613d9190849060040161484d565b5f604051808303815f87803b158015613da8575f5ffd5b505af1158015613dba573d5f5f3e3d5ffd5b505050505050505050505050565b826004613dd58282612dba565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613e17573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e3b9190615340565b613e5a576040516369c9a24560e11b81526004818101526024016108b8565b5f613e795f5160206153d65f395f51905f52546001600160a01b031690565b9050806001600160a01b03811615613ec9576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f5160206153d65f395f51905f5280546001600160a01b0319166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe70906118679088908890600401615272565b813582016020818101913590848101358501908101903582818114613f70576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b8181101561109e575f868683818110613f8d57613f8d615285565b90506020020135905060018103613fd057613fcb8a868685818110613fb457613fb4615285565b9050602002810190613fc69190614f4c565b6138dd565b61406f565b6002810361400557613fcb8a868685818110613fee57613fee615285565b90506020028101906140009190614f4c565b6139b6565b6003810361403a57613fcb8a86868581811061402357614023615285565b90506020028101906140359190614f4c565b613a74565b6004810361406f5761406f8a86868581811061405857614058615285565b905060200281019061406a9190614f4c565b613dc8565b50600101613f72565b6001600160a01b038116158061409757506001600160a01b0381166001145b156140c057604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b6001600160a01b038281165f9081526020859052604090205481169082161461410757604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b039081165f8181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b5f60605f5f5f8661ffff1667ffffffffffffffff81111561416e5761416e61470f565b6040519080825280601f01601f191660200182016040528015614198576020820181803683370190505b5090505f5f8751602089018b8e8ef191503d9250868311156141b8578692505b828152825f602083013e90999098509650505050505050565b5f8036816141e26014828789614d70565b6141eb91614d97565b60601c93506141fe603460148789614d70565b6142079161535f565b92506142168560348189614d70565b949793965094505050565b604051818382375f38838387895af161423c573d5f823e3d81fd5b3d8152602081013d5f823e3d01604052949350505050565b6040515f90828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b60608167ffffffffffffffff81111561429d5761429d61470f565b6040519080825280602002602001820160405280156142d057816020015b60608152602001906001900390816142bb5790505b509050365f5b83811015614350578484828181106142f0576142f0615285565b9050602002810190614302919061537c565b915061432b614314602084018461539a565b60208401356143266040860186614f4c565b614221565b83828151811061433d5761433d615285565b60209081029190910101526001016142d6565b505092915050565b60608167ffffffffffffffff8111156143735761437361470f565b6040519080825280602002602001820160405280156143a657816020015b60608152602001906001900390816143915790505b509050365f5b83811015614350578484828181106143c6576143c6615285565b90506020028101906143d8919061537c565b91505f6144026143eb602085018561539a565b60208501356143fd6040870187614f4c565b614254565b85848151811061441457614414615285565b6020908102919091010152905080614486577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6626144546040850185614f4c565b86858151811061446657614466615285565b602002602001015160405161447d93929190615299565b60405180910390a15b506001016143ac565b5f368161449f6014828688614d70565b6144a891614d97565b60601c92506144ba8460148188614d70565b915091509250925092565b604051818382375f388383875af46144df573d5f823e3d81fd5b3d8152602081013d5f823e3d016040529392505050565b6040515f90828482375f388483885af491503d8152602081013d5f823e3d810160405250935093915050565b604051818382375f38838387895af161453d573d5f823e3d81fd5b01604052505050565b365f5b828110156110a45783838281811061456357614563615285565b9050602002810190614575919061537c565b915061459e614587602084018461539a565b60208401356145996040860186614f4c565b614522565b600101614549565b604051818382375f388383875af46145c0573d5f823e3d81fd5b016040525050565b6001600160a01b03811615806145e757506001600160a01b0381166001145b1561461057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b038181165f90815260208490526040902054161561466c576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108b8565b60015f818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6147056060830184866146b5565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051610120810167ffffffffffffffff811182821017156147475761474761470f565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156147765761477661470f565b604052919050565b5f67ffffffffffffffff8211156147975761479761470f565b50601f01601f191660200190565b5f602082840312156147b5575f5ffd5b815167ffffffffffffffff8111156147cb575f5ffd5b8201601f810184136147db575f5ffd5b80516147ee6147e98261477e565b61474d565b818152856020838501011115614802575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610acb602083018461481f565b6001600160a01b0381168114610d45575f5ffd5b803561236d8161485f565b5f5f83601f84011261488e575f5ffd5b50813567ffffffffffffffff8111156148a5575f5ffd5b6020830191508360208285010111156148bc575f5ffd5b9250929050565b5f5f5f5f606085870312156148d6575f5ffd5b8435935060208501356148e88161485f565b9250604085013567ffffffffffffffff811115614903575f5ffd5b61490f8782880161487e565b95989497509550505050565b5f5f5f6040848603121561492d575f5ffd5b83359250602084013567ffffffffffffffff81111561494a575f5ffd5b6149568682870161487e565b9497909650939450505050565b5f6101208284031215614974575f5ffd5b50919050565b5f5f5f6060848603121561498c575f5ffd5b833567ffffffffffffffff8111156149a2575f5ffd5b6149ae86828701614963565b9660208601359650604090950135949350505050565b6001600160e01b031981168114610d45575f5ffd5b5f602082840312156149e9575f5ffd5b8135610acb816149c4565b5f5f60208385031215614a05575f5ffd5b823567ffffffffffffffff811115614a1b575f5ffd5b61277d8582860161487e565b5f5f60408385031215614a38575f5ffd5b8235614a438161485f565b946020939093013593505050565b5f5f5f60408486031215614a63575f5ffd5b8335614a6e8161485f565b9250602084013567ffffffffffffffff81111561494a575f5ffd5b604080825283519082018190525f9060208501906060840190835b81811015614acb5783516001600160a01b0316835260209384019390920191600101614aa4565b505080925050506001600160a01b03831660208301529392505050565b5f60208284031215614af8575f5ffd5b5035919050565b6001600160f81b03198816815260e060208201525f614b2160e083018961481f565b8281036040840152614b33818961481f565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614b88578351835260209384019390920191600101614b6a565b50909b9a5050505050505050505050565b5f5f60408385031215614baa575f5ffd5b823567ffffffffffffffff811115614bc0575f5ffd5b614bcc85828601614963565b95602094909401359450505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015614c3257603f19878603018452614c1d85835161481f565b94506020938401939190910190600101614c01565b50929695505050505050565b5f60208284031215614c4e575f5ffd5b813577ffffffffffffffffffffffffffffffffffffffffffffffff81168114610acb575f5ffd5b5f5f5f5f60608587031215614c88575f5ffd5b8435614c938161485f565b9350602085013567ffffffffffffffff811115614cae575f5ffd5b8501601f81018713614cbe575f5ffd5b803567ffffffffffffffff811115614cd4575f5ffd5b8760208260051b8401011115614ce8575f5ffd5b60209190910193509150604085013560ff81168114614d05575f5ffd5b939692955090935050565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52601160045260245ffd5b5f82614d5457634e487b7160e01b5f52601260045260245ffd5b500490565b808202811582820484141761113757611137614d26565b5f5f85851115614d7e575f5ffd5b83861115614d8a575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff198116906014841015614ddd576bffffffffffffffffffffffff196bffffffffffffffffffffffff198560140360031b1b82161691505b5092915050565b5f60208284031215614df4575f5ffd5b8151610acb816149c4565b5f82601f830112614e0e575f5ffd5b8135614e1c6147e98261477e565b818152846020838601011115614e30575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f6101208236031215614e5d575f5ffd5b614e65614723565b614e6e83614873565b815260208381013590820152604083013567ffffffffffffffff811115614e93575f5ffd5b614e9f36828601614dff565b604083015250606083013567ffffffffffffffff811115614ebe575f5ffd5b614eca36828601614dff565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e083013567ffffffffffffffff811115614f07575f5ffd5b614f1336828601614dff565b60e08301525061010083013567ffffffffffffffff811115614f33575f5ffd5b614f3f36828601614dff565b6101008301525092915050565b5f5f8335601e19843603018112614f61575f5ffd5b83018035915067ffffffffffffffff821115614f7b575f5ffd5b6020019150368190038213156148bc575f5ffd5b60408152614fa96040820184516001600160a01b03169052565b602083015160608201525f60408401516101206080840152614fcf61016084018261481f565b90506060850151603f198483030160a0850152614fec828261481f565b915050608085015160c084015260a085015160e084015260c085015161010084015260e0850151603f198483030161012085015261502a828261481f565b915050610100850151603f198483030161014085015261504a828261481f565b925050508260208301529392505050565b5f6020828403121561506b575f5ffd5b5051919050565b5f5f8335601e19843603018112615087575f5ffd5b830160208101925035905067ffffffffffffffff8111156150a6575f5ffd5b8036038213156148bc575f5ffd5b6150ce826150c183614873565b6001600160a01b03169052565b602081810135908301525f6150e66040830183615072565b61012060408601526150fd610120860182846146b5565b91505061510d6060840184615072565b85830360608701526151208382846146b5565b6080868101359088015260a0808701359088015260c08087013590880152925061515091505060e0840184615072565b85830360e08701526151638382846146b5565b92505050615175610100840184615072565b8583036101008701526147058382846146b5565b604081525f61519b60408301856150b4565b90508260208301529392505050565b5f5f604083850312156151bb575f5ffd5b82356151c68161485f565b9150602083013567ffffffffffffffff8111156151e1575f5ffd5b6151ed85828601614dff565b9150509250929050565b818382375f9101908152919050565b604081525f61521860408301856150b4565b8281036020840152611a6a818561481f565b8082018082111561113757611137614d26565b80356001600160e01b03198116906004841015614ddd576001600160e01b0319808560040360031b1b82161691505092915050565b602081525f6109a36020830184866146b5565b634e487b7160e01b5f52603260045260245ffd5b604081525f6152ac6040830185876146b5565b8281036020840152614705818561481f565b60ff8416815260406020820181905281018290525f8360608301825b8581101561530a5782356152ed8161485f565b6001600160a01b03168252602092830192909101906001016152da565b509695505050505050565b5f6001820161532657615326614d26565b5060010190565b8181038181111561113757611137614d26565b5f60208284031215615350575f5ffd5b81518015158114610acb575f5ffd5b80356020831015611137575f19602084900360031b1b1692915050565b5f8235605e19833603018112615390575f5ffd5b9190910192915050565b5f602082840312156153aa575f5ffd5b8135610acb8161485f56fe0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f034d6f64756c65456e61626c654d6f64652861646472657373206d6f64756c652c75696e74323536206d6f64756c65547970652c6279746573333220757365724f70486173682c6279746573333220696e6974446174614861736829a164736f6c634300081b000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
-----Decoded View---------------
Arg [0] : anEntryPoint (address): 0x0000000071727De22E5E9d8BAf0edAc6f37da032
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.