Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize | 6390750 | 173 days ago | IN | 0 ETH | 0.00039042 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
6093392 | 219 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
Kernel
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {PackedUserOperation} from "./interfaces/PackedUserOperation.sol"; import {IAccount, ValidationData, ValidAfter, ValidUntil, parseValidationData} from "./interfaces/IAccount.sol"; import {IEntryPoint} from "./interfaces/IEntryPoint.sol"; import {IAccountExecute} from "./interfaces/IAccountExecute.sol"; import {IERC7579Account} from "./interfaces/IERC7579Account.sol"; import {ModuleLib} from "./utils/ModuleLib.sol"; import { ValidationManager, ValidationMode, ValidationId, ValidatorLib, ValidationType, PermissionId, PassFlag, SKIP_SIGNATURE } from "./core/ValidationManager.sol"; import {HookManager} from "./core/HookManager.sol"; import {ExecutorManager} from "./core/ExecutorManager.sol"; import {SelectorManager} from "./core/SelectorManager.sol"; import {IModule, IValidator, IHook, IExecutor, IFallback, IPolicy, ISigner} from "./interfaces/IERC7579Modules.sol"; import {EIP712} from "solady/utils/EIP712.sol"; import {ExecLib, ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload} from "./utils/ExecLib.sol"; import { CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL, ERC1967_IMPLEMENTATION_SLOT, VALIDATION_TYPE_ROOT, VALIDATION_TYPE_VALIDATOR, VALIDATION_TYPE_PERMISSION, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK, MODULE_TYPE_HOOK, MODULE_TYPE_POLICY, MODULE_TYPE_SIGNER, EXECTYPE_TRY, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, CALLTYPE_DELEGATECALL, CALLTYPE_SINGLE, CALLTYPE_BATCH, CALLTYPE_STATIC } from "./types/Constants.sol"; contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager { error ExecutionReverted(); error InvalidExecutor(); error InvalidFallback(); error InvalidCallType(); error OnlyExecuteUserOp(); error InvalidModuleType(); error InvalidCaller(); error InvalidSelector(); error InitConfigError(uint256 idx); event Received(address sender, uint256 amount); event Upgraded(address indexed implementation); IEntryPoint public immutable entrypoint; // NOTE : when eip 1153 has been enabled, this can be transient storage mapping(bytes32 userOpHash => IHook) internal executionHook; constructor(IEntryPoint _entrypoint) { entrypoint = _entrypoint; _validationStorage().rootValidator = ValidationId.wrap(bytes21(abi.encodePacked(hex"deadbeef"))); } modifier onlyEntryPoint() { if (msg.sender != address(entrypoint)) { revert InvalidCaller(); } _; } modifier onlyEntryPointOrSelfOrRoot() { IValidator validator = ValidatorLib.getValidator(_validationStorage().rootValidator); if ( msg.sender != address(entrypoint) && msg.sender != address(this) // do rootValidator hook ) { if (validator.isModuleType(4)) { bytes memory ret = IHook(address(validator)).preCheck(msg.sender, msg.value, msg.data); _; IHook(address(validator)).postCheck(ret); } else { revert InvalidCaller(); } } else { _; } } function initialize( ValidationId _rootValidator, IHook hook, bytes calldata validatorData, bytes calldata hookData, bytes[] calldata initConfig ) external { ValidationStorage storage vs = _validationStorage(); require(ValidationId.unwrap(vs.rootValidator) == bytes21(0), "already initialized"); if (ValidationId.unwrap(_rootValidator) == bytes21(0)) { revert InvalidValidator(); } ValidationType vType = ValidatorLib.getType(_rootValidator); if (vType != VALIDATION_TYPE_VALIDATOR && vType != VALIDATION_TYPE_PERMISSION) { revert InvalidValidationType(); } _setRootValidator(_rootValidator); ValidationConfig memory config = ValidationConfig({nonce: uint32(1), hook: hook}); vs.currentNonce = 1; _installValidation(_rootValidator, config, validatorData, hookData); for (uint256 i = 0; i < initConfig.length; i++) { (bool success,) = address(this).call(initConfig[i]); if (!success) { revert InitConfigError(i); } } } function changeRootValidator( ValidationId _rootValidator, IHook hook, bytes calldata validatorData, bytes calldata hookData ) external payable onlyEntryPointOrSelfOrRoot { ValidationStorage storage vs = _validationStorage(); if (ValidationId.unwrap(_rootValidator) == bytes21(0)) { revert InvalidValidator(); } ValidationType vType = ValidatorLib.getType(_rootValidator); if (vType != VALIDATION_TYPE_VALIDATOR && vType != VALIDATION_TYPE_PERMISSION) { revert InvalidValidationType(); } _setRootValidator(_rootValidator); if (_validationStorage().validationConfig[_rootValidator].hook == IHook(address(0))) { // when new rootValidator is not installed yet ValidationConfig memory config = ValidationConfig({nonce: uint32(vs.currentNonce), hook: hook}); _installValidation(_rootValidator, config, validatorData, hookData); } } function upgradeTo(address _newImplementation) external payable onlyEntryPointOrSelfOrRoot { assembly { sstore(ERC1967_IMPLEMENTATION_SLOT, _newImplementation) } emit Upgraded(_newImplementation); } function _domainNameAndVersion() internal pure override returns (string memory name, string memory version) { name = "Kernel"; version = "0.3.1"; } receive() external payable { emit Received(msg.sender, msg.value); } function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC721Received.selector; } function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) external pure returns (bytes4) { return this.onERC1155BatchReceived.selector; } fallback() external payable { SelectorConfig memory config = _selectorConfig(msg.sig); bool success; bytes memory result; if (address(config.hook) == address(0)) { revert InvalidSelector(); } // action installed bytes memory context; if (address(config.hook) != address(1) && address(config.hook) != 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF) { context = _doPreHook(config.hook, msg.value, msg.data); } else if (address(config.hook) == 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF) { // for selector manager, address(0) for the hook will default to type(address).max, // and this will only allow entrypoints to interact if (msg.sender != address(entrypoint)) { revert InvalidCaller(); } } // execute action if (config.callType == CALLTYPE_SINGLE) { (success, result) = ExecLib.doFallback2771Call(config.target); } else if (config.callType == CALLTYPE_DELEGATECALL) { (success, result) = ExecLib.executeDelegatecall(config.target, msg.data); } else { revert NotSupportedCallType(); } if (!success) { assembly { revert(add(result, 0x20), mload(result)) } } if (address(config.hook) != address(1) && address(config.hook) != 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF) { _doPostHook(config.hook, context); } assembly { return(add(result, 0x20), mload(result)) } } // validation part function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) external payable override onlyEntryPoint returns (ValidationData validationData) { ValidationStorage storage vs = _validationStorage(); // ONLY ENTRYPOINT // Major change for v2 => v3 // 1. instead of packing 4 bytes prefix to userOp.signature to determine the mode, v3 uses userOp.nonce's first 2 bytes to check the mode // 2. instead of packing 20 bytes in userOp.signature for enable mode to provide the validator address, v3 uses userOp.nonce[2:22] // 3. In v2, only 1 plugin validator(aside from root validator) can access the selector. // In v3, you can use more than 1 plugin to use the exact selector, you need to specify the validator address in userOp.nonce[2:22] to use the validator (ValidationMode vMode, ValidationType vType, ValidationId vId) = ValidatorLib.decodeNonce(userOp.nonce); if (vType == VALIDATION_TYPE_ROOT) { vId = vs.rootValidator; } validationData = _doValidation(vMode, vId, userOp, userOpHash); ValidationConfig memory vc = vs.validationConfig[vId]; // allow when nonce is not revoked or vType is sudo if (vType != VALIDATION_TYPE_ROOT && vc.nonce < vs.validNonceFrom) { revert InvalidNonce(); } IHook execHook = vc.hook; if (address(execHook) == address(0)) { revert InvalidValidator(); } executionHook[userOpHash] = execHook; if (address(execHook) == address(1)) { // does not require hook if (vType != VALIDATION_TYPE_ROOT && !vs.allowedSelectors[vId][bytes4(userOp.callData[0:4])]) { revert InvalidValidator(); } } else { // requires hook if (vType != VALIDATION_TYPE_ROOT && !vs.allowedSelectors[vId][bytes4(userOp.callData[4:8])]) { revert InvalidValidator(); } if (bytes4(userOp.callData[0:4]) != this.executeUserOp.selector) { revert OnlyExecuteUserOp(); } } assembly { if missingAccountFunds { pop(call(gas(), caller(), missingAccountFunds, callvalue(), callvalue(), callvalue(), callvalue())) //ignore failure (its EntryPoint's job to verify, not account.) } } } // --- Execution --- function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external payable override onlyEntryPoint { bytes memory context; IHook hook = executionHook[userOpHash]; if (address(hook) != address(1)) { // removed 4bytes selector context = _doPreHook(hook, msg.value, userOp.callData[4:]); } (bool success, bytes memory ret) = ExecLib.executeDelegatecall(address(this), userOp.callData[4:]); if (!success) { revert ExecutionReverted(); } if (address(hook) != address(1)) { _doPostHook(hook, context); } } function executeFromExecutor(ExecMode execMode, bytes calldata executionCalldata) external payable returns (bytes[] memory returnData) { // no modifier needed, checking if msg.sender is registered executor will replace the modifier IHook hook = _executorConfig(IExecutor(msg.sender)).hook; if (address(hook) == address(0)) { revert InvalidExecutor(); } bytes memory context; if (address(hook) != address(1)) { context = _doPreHook(hook, msg.value, msg.data); } returnData = ExecLib.execute(execMode, executionCalldata); if (address(hook) != address(1)) { _doPostHook(hook, context); } } function execute(ExecMode execMode, bytes calldata executionCalldata) external payable onlyEntryPointOrSelfOrRoot { ExecLib.execute(execMode, executionCalldata); } function isValidSignature(bytes32 hash, bytes calldata signature) external view override returns (bytes4) { ValidationStorage storage vs = _validationStorage(); (ValidationId vId, bytes calldata sig) = ValidatorLib.decodeSignature(signature); if (ValidatorLib.getType(vId) == VALIDATION_TYPE_ROOT) { vId = vs.rootValidator; } if (address(vs.validationConfig[vId].hook) == address(0)) { revert InvalidValidator(); } if (ValidatorLib.getType(vId) == VALIDATION_TYPE_VALIDATOR) { IValidator validator = ValidatorLib.getValidator(vId); return validator.isValidSignatureWithSender(msg.sender, _toWrappedHash(hash), sig); } else { PermissionId pId = ValidatorLib.getPermissionId(vId); PassFlag permissionFlag = vs.permissionConfig[pId].permissionFlag; if (PassFlag.unwrap(permissionFlag) & PassFlag.unwrap(SKIP_SIGNATURE) != 0) { revert PermissionNotAlllowedForSignature(); } return _checkPermissionSignature(pId, msg.sender, hash, sig); } } function installModule(uint256 moduleType, address module, bytes calldata initData) external payable override onlyEntryPointOrSelfOrRoot { if (moduleType == MODULE_TYPE_VALIDATOR) { ValidationStorage storage vs = _validationStorage(); ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(module)); if (vs.validationConfig[vId].nonce == vs.currentNonce) { // only increase currentNonce when vId's currentNonce is same unchecked { vs.currentNonce++; } } ValidationConfig memory config = ValidationConfig({nonce: vs.currentNonce, hook: IHook(address(bytes20(initData[0:20])))}); bytes calldata validatorData; bytes calldata hookData; bytes calldata selectorData; assembly { validatorData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 20))) validatorData.length := calldataload(sub(validatorData.offset, 32)) hookData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 52))) hookData.length := calldataload(sub(hookData.offset, 32)) selectorData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 84))) selectorData.length := calldataload(sub(selectorData.offset, 32)) } _installValidation(vId, config, validatorData, hookData); if (selectorData.length == 4) { // NOTE: we don't allow configure on selector data on v3.1, but using bytes instead of bytes4 for selector data to make sure we are future proof _setSelector(vId, bytes4(selectorData[0:4]), true); } } else if (moduleType == MODULE_TYPE_EXECUTOR) { bytes calldata executorData; bytes calldata hookData; assembly { executorData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 20))) executorData.length := calldataload(sub(executorData.offset, 32)) hookData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 52))) hookData.length := calldataload(sub(hookData.offset, 32)) } IHook hook = IHook(address(bytes20(initData[0:20]))); _installExecutor(IExecutor(module), executorData, hook); _installHook(hook, hookData); } else if (moduleType == MODULE_TYPE_FALLBACK) { bytes calldata selectorData; bytes calldata hookData; assembly { selectorData.offset := add(add(initData.offset, 56), calldataload(add(initData.offset, 24))) selectorData.length := calldataload(sub(selectorData.offset, 32)) hookData.offset := add(add(initData.offset, 56), calldataload(add(initData.offset, 56))) hookData.length := calldataload(sub(hookData.offset, 32)) } _installSelector(bytes4(initData[0:4]), module, IHook(address(bytes20(initData[4:24]))), selectorData); _installHook(IHook(address(bytes20(initData[4:24]))), hookData); } else if (moduleType == MODULE_TYPE_HOOK) { // force call onInstall for hook // NOTE: for hook, kernel does not support independent hook install, // hook is expected to be paired with proper validator/executor/selector IHook(module).onInstall(initData); emit ModuleInstalled(moduleType, module); } else if (moduleType == MODULE_TYPE_POLICY) { // force call onInstall for policy // NOTE: for policy, kernel does not support independent policy install, // policy is expected to be paired with proper permissionId // to "ADD" permission, use "installValidations()" function IPolicy(module).onInstall(initData); emit ModuleInstalled(moduleType, module); } else if (moduleType == MODULE_TYPE_SIGNER) { // force call onInstall for signer // NOTE: for signer, kernel does not support independent signer install, // signer is expected to be paired with proper permissionId // to "ADD" permission, use "installValidations()" function ISigner(module).onInstall(initData); emit ModuleInstalled(moduleType, module); } else { revert InvalidModuleType(); } } function installValidations( ValidationId[] calldata vIds, ValidationConfig[] memory configs, bytes[] calldata validationData, bytes[] calldata hookData ) external payable onlyEntryPointOrSelfOrRoot { _installValidations(vIds, configs, validationData, hookData); } function uninstallValidation(ValidationId vId, bytes calldata deinitData, bytes calldata hookDeinitData) external payable onlyEntryPointOrSelfOrRoot { IHook hook = _uninstallValidation(vId, deinitData); _uninstallHook(hook, hookDeinitData); } function invalidateNonce(uint32 nonce) external payable onlyEntryPointOrSelfOrRoot { _invalidateNonce(nonce); } function uninstallModule(uint256 moduleType, address module, bytes calldata deInitData) external payable override onlyEntryPointOrSelfOrRoot { if (moduleType == 1) { ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(module)); _uninstallValidation(vId, deInitData); } else if (moduleType == 2) { _uninstallExecutor(IExecutor(module), deInitData); } else if (moduleType == 3) { bytes4 selector = bytes4(deInitData[0:4]); _uninstallSelector(selector, deInitData[4:]); } else if (moduleType == 4) { ValidationId vId = _validationStorage().rootValidator; if (_validationStorage().validationConfig[vId].hook == IHook(module)) { // when root validator hook is being removed // remove hook on root validator to prevent kernel from being locked _validationStorage().validationConfig[vId].hook = IHook(address(1)); } // force call onUninstall for hook // NOTE: for hook, kernel does not support independent hook install, // hook is expected to be paired with proper validator/executor/selector ModuleLib.uninstallModule(module, deInitData); emit ModuleUninstalled(moduleType, module); } else if (moduleType == 5) { ValidationId rootValidator = _validationStorage().rootValidator; bytes32 permissionId = bytes32(deInitData[0:32]); if (ValidatorLib.getType(rootValidator) == VALIDATION_TYPE_PERMISSION) { if (permissionId == bytes32(PermissionId.unwrap(ValidatorLib.getPermissionId(rootValidator)))) { revert RootValidatorCannotBeRemoved(); } } // force call onUninstall for policy // NOTE: for policy, kernel does not support independent policy install, // policy is expected to be paired with proper permissionId // to "REMOVE" permission, use "uninstallValidation()" function ModuleLib.uninstallModule(module, deInitData); emit ModuleUninstalled(moduleType, module); } else if (moduleType == 6) { ValidationId rootValidator = _validationStorage().rootValidator; bytes32 permissionId = bytes32(deInitData[0:32]); if (ValidatorLib.getType(rootValidator) == VALIDATION_TYPE_PERMISSION) { if (permissionId == bytes32(PermissionId.unwrap(ValidatorLib.getPermissionId(rootValidator)))) { revert RootValidatorCannotBeRemoved(); } } // force call onUninstall for signer // NOTE: for signer, kernel does not support independent signer install, // signer is expected to be paired with proper permissionId // to "REMOVE" permission, use "uninstallValidation()" function ModuleLib.uninstallModule(module, deInitData); emit ModuleUninstalled(moduleType, module); } else { revert InvalidModuleType(); } } function supportsModule(uint256 moduleTypeId) external pure override returns (bool) { if (moduleTypeId < 7) { return true; } else { return false; } } function isModuleInstalled(uint256 moduleType, address module, bytes calldata additionalContext) external view override returns (bool) { if (moduleType == MODULE_TYPE_VALIDATOR) { return _validationStorage().validationConfig[ValidatorLib.validatorToIdentifier(IValidator(module))].hook != IHook(address(0)); } else if (moduleType == MODULE_TYPE_EXECUTOR) { return address(_executorConfig(IExecutor(module)).hook) != address(0); } else if (moduleType == MODULE_TYPE_FALLBACK) { return _selectorConfig(bytes4(additionalContext[0:4])).target == module; } else { return false; } } function accountId() external pure override returns (string memory accountImplementationId) { return "kernel.advanced.v0.3.1"; } function supportsExecutionMode(ExecMode mode) external pure override returns (bool) { (CallType callType, ExecType execType, ExecModeSelector selector, ExecModePayload payload) = ExecLib.decode(mode); if ( callType != CALLTYPE_BATCH && callType != CALLTYPE_SINGLE && callType != CALLTYPE_DELEGATECALL && callType != CALLTYPE_STATIC ) { return false; } if ( ExecType.unwrap(execType) != ExecType.unwrap(EXECTYPE_TRY) && ExecType.unwrap(execType) != ExecType.unwrap(EXECTYPE_DEFAULT) ) { return false; } if (ExecModeSelector.unwrap(selector) != ExecModeSelector.unwrap(EXEC_MODE_DEFAULT)) { return false; } if (ExecModePayload.unwrap(payload) != bytes22(0)) { return false; } return true; } }
// 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 maxFeePerGas and maxPriorityFeePerGas - Same as EIP-1559 gas parameter. * @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; //maxPriorityFee and maxFeePerGas; bytes paymasterAndData; bytes signature; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.5; import "./PackedUserOperation.sol"; import "../types/Types.sol"; interface IAccount { /** * Validate user's signature and nonce * the entryPoint will make the call to the recipient only if this validation call returns successfully. * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). * This allows making a "simulation call" without a valid signature * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure. * * @dev Must validate caller is the entryPoint. * Must validate the signature and nonce * @param userOp - The operation that is about to be executed. * @param userOpHash - Hash of the user's request data. can be used as the basis for signature. * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint. * This is the minimum amount to transfer to the sender(entryPoint) to be * able to make the call. The excess is left as a deposit in the entrypoint * for future calls. Can be withdrawn anytime using "entryPoint.withdrawTo()". * In case there is a paymaster in the request (or the current deposit is high * enough), this value will be zero. * @return validationData - Packaged ValidationData structure. use `_packValidationData` and * `_unpackValidationData` to encode and decode. * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, * otherwise, an address of an "authorizer" contract. * <6-byte> validUntil - Last timestamp this operation is valid. 0 for "indefinite" * <6-byte> validAfter - First timestamp this operation is valid * If an account doesn't use time-range, it is enough to * return SIG_VALIDATION_FAILED value (1) for signature failure. * Note that the validation code cannot use block.timestamp (or block.number) directly. */ function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) external payable returns (ValidationData validationData); }
// SPDX-License-Identifier: GPL-3.0 /** * Account-Abstraction (EIP-4337) singleton EntryPoint implementation. * Only one instance required on each chain. * */ 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); /** * 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 caught 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: GPL-3.0 pragma solidity >=0.7.5; import "./PackedUserOperation.sol"; interface IAccountExecute { /** * Account may implement this execute method. * passing this methodSig at the beginning of callData will cause the entryPoint to pass the full UserOp (and hash) * to the account. * The account should skip the methodSig, and use the callData (and optionally, other UserOp fields) * * @param userOp - The operation that was just validated. * @param userOpHash - Hash of the user's request data. */ function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import {CallType, ExecType, ExecMode} from "../utils/ExecLib.sol"; import {PackedUserOperation} from "./PackedUserOperation.sol"; struct Execution { address target; uint256 value; bytes callData; } interface IERC7579Account { event ModuleInstalled(uint256 moduleTypeId, address module); event ModuleUninstalled(uint256 moduleTypeId, address module); /** * @dev Executes a transaction on behalf of the account. * This function is intended to be called by ERC-4337 EntryPoint.sol * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf * * @dev MSA MUST implement this function signature. * If a mode is requested that is not supported by the Account, it MUST revert * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details * @param executionCalldata The encoded execution call data */ function execute(ExecMode mode, bytes calldata executionCalldata) external payable; /** * @dev Executes a transaction on behalf of the account. * This function is intended to be called by Executor Modules * @dev Ensure adequate authorization control: i.e. onlyExecutorModule * * @dev MSA MUST implement this function signature. * If a mode is requested that is not supported by the Account, it MUST revert * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details * @param executionCalldata The encoded execution call data */ function executeFromExecutor(ExecMode mode, bytes calldata executionCalldata) external payable returns (bytes[] memory returnData); /** * @dev ERC-1271 isValidSignature * This function is intended to be used to validate a smart account signature * and may forward the call to a validator module * * @param hash The hash of the data that is signed * @param data The data that is signed */ function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4); /** * @dev installs a Module of a certain type on the smart account * @dev Implement Authorization control of your choosing * @param moduleTypeId the module type ID according the ERC-7579 spec * @param module the module address * @param initData arbitrary data that may be required on the module during `onInstall` * initialization. */ function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable; /** * @dev uninstalls a Module of a certain type on the smart account * @dev Implement Authorization control of your choosing * @param moduleTypeId the module type ID according the ERC-7579 spec * @param module the module address * @param deInitData arbitrary data that may be required on the module during `onUninstall` * de-initialization. */ function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable; /** * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) * @param encodedMode the encoded mode */ function supportsExecutionMode(ExecMode encodedMode) external view returns (bool); /** * Function to check if the account supports installation of a certain module type Id * @param moduleTypeId the module type ID according the ERC-7579 spec */ function supportsModule(uint256 moduleTypeId) external view returns (bool); /** * Function to check if the account has a certain module installed * @param moduleTypeId the module type ID according the ERC-7579 spec * Note: keep in mind that some contracts can be multiple module types at the same time. It * thus may be necessary to query multiple module types * @param module the module address * @param additionalContext additional context data that the smart account may interpret to * identify conditions under which the module is installed. * usually this is not necessary, but for some special hooks that * are stored in mappings, this param might be needed */ function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) external view returns (bool); /** * @dev Returns the account id of the smart account * @return accountImplementationId the account id of the smart account * the accountId should be structured like so: * "vendorname.accountname.semver" */ function accountId() external view returns (string memory accountImplementationId); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ExcessivelySafeCall} from "ExcessivelySafeCall/ExcessivelySafeCall.sol"; import {IModule} from "../interfaces/IERC7579Modules.sol"; library ModuleLib { event ModuleUninstallResult(address module, bool result); function uninstallModule(address module, bytes memory deinitData) internal returns (bool result) { (result,) = ExcessivelySafeCall.excessivelySafeCall( module, gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, deinitData) ); emit ModuleUninstallResult(module, result); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IValidator, IModule, IExecutor, IHook, IPolicy, ISigner, IFallback} from "../interfaces/IERC7579Modules.sol"; import {IERC7579Account} from "../interfaces/IERC7579Account.sol"; import {PackedUserOperation} from "../interfaces/PackedUserOperation.sol"; import {SelectorManager} from "./SelectorManager.sol"; import {HookManager} from "./HookManager.sol"; import {ExecutorManager} from "./ExecutorManager.sol"; import {ValidationData, ValidAfter, ValidUntil, parseValidationData} from "../interfaces/IAccount.sol"; import {IAccountExecute} from "../interfaces/IAccountExecute.sol"; import {EIP712} from "solady/utils/EIP712.sol"; import {ModuleLib} from "../utils/ModuleLib.sol"; import { ValidationId, PolicyData, ValidationMode, ValidationType, ValidatorLib, PassFlag } from "../utils/ValidationTypeLib.sol"; import {CallType} from "../utils/ExecLib.sol"; import {CALLTYPE_SINGLE, MODULE_TYPE_POLICY, MODULE_TYPE_SIGNER, MODULE_TYPE_VALIDATOR} from "../types/Constants.sol"; import {PermissionId, getValidationResult} from "../types/Types.sol"; import {_intersectValidationData} from "../utils/KernelValidationResult.sol"; import { VALIDATION_MODE_DEFAULT, VALIDATION_MODE_ENABLE, VALIDATION_TYPE_ROOT, VALIDATION_TYPE_VALIDATOR, VALIDATION_TYPE_PERMISSION, SKIP_USEROP, SKIP_SIGNATURE, VALIDATION_MANAGER_STORAGE_SLOT, MAX_NONCE_INCREMENT_SIZE, ENABLE_TYPE_HASH, KERNEL_WRAPPER_TYPE_HASH } from "../types/Constants.sol"; abstract contract ValidationManager is EIP712, SelectorManager, HookManager, ExecutorManager { event RootValidatorUpdated(ValidationId rootValidator); event ValidatorInstalled(IValidator validator, uint32 nonce); event PermissionInstalled(PermissionId permission, uint32 nonce); event NonceInvalidated(uint32 nonce); event ValidatorUninstalled(IValidator validator); event PermissionUninstalled(PermissionId permission); event SelectorSet(bytes4 selector, ValidationId vId, bool allowed); error InvalidMode(); error InvalidValidator(); error InvalidSignature(); error EnableNotApproved(); error PolicySignatureOrderError(); error SignerPrefixNotPresent(); error PolicyDataTooLarge(); error InvalidValidationType(); error InvalidNonce(); error PolicyFailed(uint256 i); error PermissionNotAlllowedForUserOp(); error PermissionNotAlllowedForSignature(); error PermissionDataLengthMismatch(); error NonceInvalidationError(); error RootValidatorCannotBeRemoved(); // erc7579 plugins struct ValidationConfig { uint32 nonce; // 4 bytes IHook hook; // 20 bytes address(1) : hook not required, address(0) : validator not installed } struct PermissionConfig { PassFlag permissionFlag; ISigner signer; PolicyData[] policyData; } struct ValidationStorage { ValidationId rootValidator; uint32 currentNonce; uint32 validNonceFrom; mapping(ValidationId => ValidationConfig) validationConfig; mapping(ValidationId => mapping(bytes4 => bool)) allowedSelectors; // validation = validator | permission // validator == 1 validator // permission == 1 signer + N policies mapping(PermissionId => PermissionConfig) permissionConfig; } function rootValidator() external view returns (ValidationId) { return _validationStorage().rootValidator; } function currentNonce() external view returns (uint32) { return _validationStorage().currentNonce; } function validNonceFrom() external view returns (uint32) { return _validationStorage().validNonceFrom; } function isAllowedSelector(ValidationId vId, bytes4 selector) external view returns (bool) { return _validationStorage().allowedSelectors[vId][selector]; } function validationConfig(ValidationId vId) external view returns (ValidationConfig memory) { return _validationStorage().validationConfig[vId]; } function permissionConfig(PermissionId pId) external view returns (PermissionConfig memory) { return (_validationStorage().permissionConfig[pId]); } function _validationStorage() internal pure returns (ValidationStorage storage state) { assembly { state.slot := VALIDATION_MANAGER_STORAGE_SLOT } } function _setRootValidator(ValidationId _rootValidator) internal { ValidationStorage storage vs = _validationStorage(); vs.rootValidator = _rootValidator; emit RootValidatorUpdated(_rootValidator); } function _invalidateNonce(uint32 nonce) internal { ValidationStorage storage state = _validationStorage(); if (state.currentNonce + MAX_NONCE_INCREMENT_SIZE < nonce) { revert NonceInvalidationError(); } if (nonce <= state.validNonceFrom) { revert InvalidNonce(); } state.validNonceFrom = nonce; if (state.currentNonce < state.validNonceFrom) { state.currentNonce = state.validNonceFrom; } } // allow installing multiple validators with same nonce function _installValidations( ValidationId[] calldata validators, ValidationConfig[] memory configs, bytes[] calldata validatorData, bytes[] calldata hookData ) internal { unchecked { for (uint256 i = 0; i < validators.length; i++) { _installValidation(validators[i], configs[i], validatorData[i], hookData[i]); } } } function _setSelector(ValidationId vId, bytes4 selector, bool allowed) internal { ValidationStorage storage state = _validationStorage(); state.allowedSelectors[vId][selector] = allowed; emit SelectorSet(selector, vId, allowed); } // for uninstall, we support uninstall for validator mode by calling onUninstall // but for permission mode, we do it naively by setting hook to address(0). // it is more recommended to use a nonce revoke to make sure the validator has been revoked // also, we are not calling hook.onInstall here function _uninstallValidation(ValidationId vId, bytes calldata validatorData) internal returns (IHook hook) { ValidationStorage storage state = _validationStorage(); if (vId == state.rootValidator) { revert RootValidatorCannotBeRemoved(); } hook = state.validationConfig[vId].hook; state.validationConfig[vId].hook = IHook(address(0)); ValidationType vType = ValidatorLib.getType(vId); if (vType == VALIDATION_TYPE_VALIDATOR) { IValidator validator = ValidatorLib.getValidator(vId); ModuleLib.uninstallModule(address(validator), validatorData); emit IERC7579Account.ModuleUninstalled(MODULE_TYPE_VALIDATOR, address(validator)); } else if (vType == VALIDATION_TYPE_PERMISSION) { PermissionId permission = ValidatorLib.getPermissionId(vId); _uninstallPermission(permission, validatorData); } else { revert InvalidValidationType(); } } function _uninstallPermission(PermissionId pId, bytes calldata data) internal { bytes[] calldata permissionDisableData; assembly { permissionDisableData.offset := add(add(data.offset, 32), calldataload(data.offset)) permissionDisableData.length := calldataload(sub(permissionDisableData.offset, 32)) } PermissionConfig storage config = _validationStorage().permissionConfig[pId]; unchecked { if (permissionDisableData.length != config.policyData.length + 1) { revert PermissionDataLengthMismatch(); } PolicyData[] storage policyData = config.policyData; for (uint256 i = 0; i < policyData.length; i++) { (, IPolicy policy) = ValidatorLib.decodePolicyData(policyData[i]); ModuleLib.uninstallModule( address(policy), abi.encodePacked(bytes32(PermissionId.unwrap(pId)), permissionDisableData[i]) ); emit IERC7579Account.ModuleUninstalled(MODULE_TYPE_POLICY, address(policy)); } delete _validationStorage().permissionConfig[pId].policyData; ModuleLib.uninstallModule( address(config.signer), abi.encodePacked( bytes32(PermissionId.unwrap(pId)), permissionDisableData[permissionDisableData.length - 1] ) ); emit IERC7579Account.ModuleUninstalled(MODULE_TYPE_SIGNER, address(config.signer)); } config.signer = ISigner(address(0)); config.permissionFlag = PassFlag.wrap(bytes2(0)); } function _installValidation( ValidationId vId, ValidationConfig memory config, bytes calldata validatorData, bytes calldata hookData ) internal { ValidationStorage storage state = _validationStorage(); if (state.validationConfig[vId].nonce == state.currentNonce) { // only increase currentNonce when vId's currentNonce is same unchecked { state.currentNonce++; } } if (config.hook == IHook(address(0))) { config.hook = IHook(address(1)); } if (state.currentNonce != config.nonce || state.validationConfig[vId].nonce >= config.nonce) { revert InvalidNonce(); } state.validationConfig[vId] = config; if (config.hook != IHook(address(1))) { _installHook(config.hook, hookData); } ValidationType vType = ValidatorLib.getType(vId); if (vType == VALIDATION_TYPE_VALIDATOR) { IValidator validator = ValidatorLib.getValidator(vId); validator.onInstall(validatorData); emit IERC7579Account.ModuleInstalled(MODULE_TYPE_VALIDATOR, address(validator)); } else if (vType == VALIDATION_TYPE_PERMISSION) { PermissionId permission = ValidatorLib.getPermissionId(vId); _installPermission(permission, validatorData); } else { revert InvalidValidationType(); } } function _installPermission(PermissionId permission, bytes calldata data) internal { ValidationStorage storage state = _validationStorage(); bytes[] calldata permissionEnableData; assembly { permissionEnableData.offset := add(add(data.offset, 32), calldataload(data.offset)) permissionEnableData.length := calldataload(sub(permissionEnableData.offset, 32)) } // allow up to 0xfe, 0xff is dedicated for signer if (permissionEnableData.length > 254 || permissionEnableData.length == 0) { revert PolicyDataTooLarge(); } // clean up the policyData if (state.permissionConfig[permission].policyData.length > 0) { delete state.permissionConfig[permission].policyData; } unchecked { for (uint256 i = 0; i < permissionEnableData.length - 1; i++) { state.permissionConfig[permission].policyData.push( PolicyData.wrap(bytes22(permissionEnableData[i][0:22])) ); IPolicy(address(bytes20(permissionEnableData[i][2:22]))).onInstall( abi.encodePacked(bytes32(PermissionId.unwrap(permission)), permissionEnableData[i][22:]) ); emit IERC7579Account.ModuleInstalled( MODULE_TYPE_POLICY, address(bytes20(permissionEnableData[i][2:22])) ); } // last permission data will be signer ISigner signer = ISigner(address(bytes20(permissionEnableData[permissionEnableData.length - 1][2:22]))); state.permissionConfig[permission].signer = signer; state.permissionConfig[permission].permissionFlag = PassFlag.wrap(bytes2(permissionEnableData[permissionEnableData.length - 1][0:2])); signer.onInstall( abi.encodePacked( bytes32(PermissionId.unwrap(permission)), permissionEnableData[permissionEnableData.length - 1][22:] ) ); emit IERC7579Account.ModuleInstalled(MODULE_TYPE_SIGNER, address(signer)); } } function _doValidation(ValidationMode vMode, ValidationId vId, PackedUserOperation calldata op, bytes32 userOpHash) internal returns (ValidationData validationData) { ValidationStorage storage state = _validationStorage(); PackedUserOperation memory userOp = op; bytes calldata userOpSig = op.signature; unchecked { if (vMode == VALIDATION_MODE_ENABLE) { (validationData, userOpSig) = _enableMode(vId, op.signature); userOp.signature = userOpSig; } ValidationType vType = ValidatorLib.getType(vId); if (vType == VALIDATION_TYPE_VALIDATOR) { validationData = _intersectValidationData( validationData, ValidationData.wrap(ValidatorLib.getValidator(vId).validateUserOp(userOp, userOpHash)) ); } else { PermissionId pId = ValidatorLib.getPermissionId(vId); if (PassFlag.unwrap(state.permissionConfig[pId].permissionFlag) & PassFlag.unwrap(SKIP_USEROP) != 0) { revert PermissionNotAlllowedForUserOp(); } (ValidationData policyCheck, ISigner signer) = _checkUserOpPolicy(pId, userOp, userOpSig); validationData = _intersectValidationData(validationData, policyCheck); validationData = _intersectValidationData( validationData, ValidationData.wrap( signer.checkUserOpSignature(bytes32(PermissionId.unwrap(pId)), userOp, userOpHash) ) ); } } } function _enableMode(ValidationId vId, bytes calldata packedData) internal returns (ValidationData validationData, bytes calldata userOpSig) { validationData = _enableValidationWithSig(vId, packedData); assembly { userOpSig.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 148))) userOpSig.length := calldataload(sub(userOpSig.offset, 32)) } return (validationData, userOpSig); } function _enableValidationWithSig(ValidationId vId, bytes calldata packedData) internal returns (ValidationData validationData) { bytes calldata enableSig; ( ValidationConfig memory config, bytes calldata validatorData, bytes calldata hookData, bytes calldata selectorData, bytes32 digest ) = _enableDigest(vId, packedData); assembly { enableSig.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 116))) enableSig.length := calldataload(sub(enableSig.offset, 32)) } validationData = _checkEnableSig(digest, enableSig); _installValidation(vId, config, validatorData, hookData); _configureSelector(selectorData); _setSelector(vId, bytes4(selectorData[0:4]), true); } function _checkEnableSig(bytes32 digest, bytes calldata enableSig) internal view returns (ValidationData validationData) { ValidationStorage storage state = _validationStorage(); ValidationType vType = ValidatorLib.getType(state.rootValidator); bytes4 result; if (vType == VALIDATION_TYPE_VALIDATOR) { IValidator validator = ValidatorLib.getValidator(state.rootValidator); result = validator.isValidSignatureWithSender(address(this), digest, enableSig); } else if (vType == VALIDATION_TYPE_PERMISSION) { PermissionId pId = ValidatorLib.getPermissionId(state.rootValidator); ISigner signer; (signer, validationData, enableSig) = _checkSignaturePolicy(pId, address(this), digest, enableSig); result = signer.checkSignature(bytes32(PermissionId.unwrap(pId)), address(this), digest, enableSig); } else { revert InvalidValidationType(); } if (result != 0x1626ba7e) { revert EnableNotApproved(); } } function _configureSelector(bytes calldata selectorData) internal { bytes4 selector = bytes4(selectorData[0:4]); if (selectorData.length >= 4) { if (selectorData.length >= 44) { // install selector with hook and target contract bytes calldata selectorInitData; bytes calldata hookInitData; IModule selectorModule = IModule(address(bytes20(selectorData[4:24]))); assembly { selectorInitData.offset := add(add(selectorData.offset, 76), calldataload(add(selectorData.offset, 44))) selectorInitData.length := calldataload(sub(selectorInitData.offset, 32)) hookInitData.offset := add(add(selectorData.offset, 76), calldataload(add(selectorData.offset, 76))) hookInitData.length := calldataload(sub(hookInitData.offset, 32)) } if (CallType.wrap(bytes1(selectorInitData[0])) == CALLTYPE_SINGLE && selectorModule.isModuleType(2)) { // also adds as executor when fallback module is also a executor bytes calldata executorHookData; assembly { executorHookData.offset := add(add(selectorData.offset, 76), calldataload(add(selectorData.offset, 108))) executorHookData.length := calldataload(sub(executorHookData.offset, 32)) } IHook executorHook = IHook(address(bytes20(executorHookData[0:20]))); // if module is also executor, install as executor _installExecutorWithoutInit(IExecutor(address(selectorModule)), executorHook); _installHook(executorHook, executorHookData[20:]); } _installSelector( selector, address(selectorModule), IHook(address(bytes20(selectorData[24:44]))), selectorInitData ); _installHook(IHook(address(bytes20(selectorData[24:44]))), hookInitData); } else { // set without install require(selectorData.length == 4, "Invalid selectorData"); } } } function _enableDigest(ValidationId vId, bytes calldata packedData) internal view returns ( ValidationConfig memory config, bytes calldata validatorData, bytes calldata hookData, bytes calldata selectorData, bytes32 digest ) { ValidationStorage storage state = _validationStorage(); config.hook = IHook(address(bytes20(packedData[0:20]))); config.nonce = state.currentNonce; assembly { validatorData.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 20))) validatorData.length := calldataload(sub(validatorData.offset, 32)) hookData.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 52))) hookData.length := calldataload(sub(hookData.offset, 32)) selectorData.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 84))) selectorData.length := calldataload(sub(selectorData.offset, 32)) } digest = _hashTypedData( keccak256( abi.encode( ENABLE_TYPE_HASH, ValidationId.unwrap(vId), state.currentNonce, config.hook, keccak256(validatorData), keccak256(hookData), keccak256(selectorData) ) ) ); } struct PermissionSigMemory { uint8 idx; uint256 length; ValidationData validationData; PermissionId permission; PassFlag flag; IPolicy policy; bytes permSig; address caller; bytes32 digest; } function _checkUserOpPolicy(PermissionId pId, PackedUserOperation memory userOp, bytes calldata userOpSig) internal returns (ValidationData validationData, ISigner signer) { ValidationStorage storage state = _validationStorage(); PolicyData[] storage policyData = state.permissionConfig[pId].policyData; unchecked { for (uint256 i = 0; i < policyData.length; i++) { (PassFlag flag, IPolicy policy) = ValidatorLib.decodePolicyData(policyData[i]); uint8 idx = uint8(bytes1(userOpSig[0])); if (idx == i) { // we are using uint64 length uint256 length = uint64(bytes8(userOpSig[1:9])); userOp.signature = userOpSig[9:9 + length]; userOpSig = userOpSig[9 + length:]; } else if (idx < i) { // signature is not in order revert PolicySignatureOrderError(); } else { userOp.signature = ""; } if (PassFlag.unwrap(flag) & PassFlag.unwrap(SKIP_USEROP) == 0) { ValidationData vd = ValidationData.wrap(policy.checkUserOpPolicy(bytes32(PermissionId.unwrap(pId)), userOp)); address result = getValidationResult(vd); if (result != address(0)) { revert PolicyFailed(i); } validationData = _intersectValidationData(validationData, vd); } } if (uint8(bytes1(userOpSig[0])) != 255) { revert SignerPrefixNotPresent(); } userOp.signature = userOpSig[1:]; return (validationData, state.permissionConfig[pId].signer); } } function _checkSignaturePolicy(PermissionId pId, address caller, bytes32 digest, bytes calldata sig) internal view returns (ISigner, ValidationData, bytes calldata) { ValidationStorage storage state = _validationStorage(); PermissionSigMemory memory mSig; mSig.permission = pId; mSig.caller = caller; mSig.digest = digest; _checkPermissionPolicy(mSig, state, sig); if (uint8(bytes1(sig[0])) != 255) { revert SignerPrefixNotPresent(); } sig = sig[1:]; return (state.permissionConfig[mSig.permission].signer, mSig.validationData, sig); } function _checkPermissionPolicy( PermissionSigMemory memory mSig, ValidationStorage storage state, bytes calldata sig ) internal view { PolicyData[] storage policyData = state.permissionConfig[mSig.permission].policyData; unchecked { for (uint256 i = 0; i < policyData.length; i++) { (mSig.flag, mSig.policy) = ValidatorLib.decodePolicyData(policyData[i]); mSig.idx = uint8(bytes1(sig[0])); if (mSig.idx == i) { // we are using uint64 length mSig.length = uint64(bytes8(sig[1:9])); mSig.permSig = sig[9:9 + mSig.length]; sig = sig[9 + mSig.length:]; } else if (mSig.idx < i) { // signature is not in order revert PolicySignatureOrderError(); } else { mSig.permSig = sig[0:0]; } if (PassFlag.unwrap(mSig.flag) & PassFlag.unwrap(SKIP_SIGNATURE) == 0) { ValidationData vd = ValidationData.wrap( mSig.policy.checkSignaturePolicy( bytes32(PermissionId.unwrap(mSig.permission)), mSig.caller, mSig.digest, mSig.permSig ) ); address result = getValidationResult(vd); if (result != address(0)) { revert PolicyFailed(i); } mSig.validationData = _intersectValidationData(mSig.validationData, vd); } } } } function _checkPermissionSignature(PermissionId pId, address caller, bytes32 hash, bytes calldata sig) internal view returns (bytes4) { (ISigner signer, ValidationData valdiationData, bytes calldata validatorSig) = _checkSignaturePolicy(pId, caller, hash, sig); (ValidAfter validAfter, ValidUntil validUntil,) = parseValidationData(ValidationData.unwrap(valdiationData)); if (block.timestamp < ValidAfter.unwrap(validAfter) || block.timestamp > ValidUntil.unwrap(validUntil)) { return 0xffffffff; } return signer.checkSignature(bytes32(PermissionId.unwrap(pId)), caller, _toWrappedHash(hash), validatorSig); } function _toWrappedHash(bytes32 hash) internal view returns (bytes32) { return _hashTypedData(keccak256(abi.encode(KERNEL_WRAPPER_TYPE_HASH, hash))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IHook} from "../interfaces/IERC7579Modules.sol"; import {ModuleLib} from "../utils/ModuleLib.sol"; import {IERC7579Account} from "../interfaces/IERC7579Account.sol"; import {MODULE_TYPE_HOOK} from "../types/Constants.sol"; abstract contract HookManager { // NOTE: currently, all install/uninstall calls onInstall/onUninstall // I assume this does not pose any security risks, but there should be a way to branch if hook needs call to onInstall/onUninstall // --- Hook --- // Hook is activated on these scenarios // - on 4337 flow, userOp.calldata starts with executeUserOp.selector && validator requires hook // - executeFromExecutor() is invoked and executor requires hook // - when fallback function has been invoked and fallback requires hook => native functions will not invoke hook function _doPreHook(IHook hook, uint256 value, bytes calldata callData) internal returns (bytes memory context) { context = hook.preCheck(msg.sender, value, callData); } function _doPostHook(IHook hook, bytes memory context) internal { // bool success, // bytes memory result hook.postCheck(context); } // @notice if hook is not initialized before, kernel will call hook.onInstall no matter what flag it shows, with hookData[1:] // @param hookData is encoded into (1bytes flag + actual hookdata) flag is for identifying if the hook has to be initialized or not function _installHook(IHook hook, bytes calldata hookData) internal { if (address(hook) == address(0) || address(hook) == address(1)) { return; } if (!hook.isInitialized(address(this))) { // if hook is not installed, it should call onInstall hook.onInstall(hookData[1:]); } else if (bytes1(hookData[0]) == bytes1(0xff)) { // 0xff means you want to explicitly call install hook hook.onInstall(hookData[1:]); } emit IERC7579Account.ModuleInstalled(MODULE_TYPE_HOOK, address(hook)); } // @param hookData encoded as (1bytes flag + actual hookdata) flag is for identifying if the hook has to be initialized or not function _uninstallHook(IHook hook, bytes calldata hookData) internal { if (address(hook) == address(0) || address(hook) == address(1)) { return; } if (bytes1(hookData[0]) == bytes1(0xff)) { // 0xff means you want to call uninstall hook ModuleLib.uninstallModule(address(hook), hookData[1:]); } emit IERC7579Account.ModuleUninstalled(MODULE_TYPE_HOOK, address(hook)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IHook, IExecutor} from "../interfaces/IERC7579Modules.sol"; import {IERC7579Account} from "../interfaces/IERC7579Account.sol"; import {ModuleLib} from "../utils/ModuleLib.sol"; import {EXECUTOR_MANAGER_STORAGE_SLOT, MODULE_TYPE_EXECUTOR} from "../types/Constants.sol"; abstract contract ExecutorManager { struct ExecutorConfig { IHook hook; // address(1) : hook not required, address(0) : validator not installed } struct ExecutorStorage { mapping(IExecutor => ExecutorConfig) executorConfig; } function executorConfig(IExecutor executor) external view returns (ExecutorConfig memory) { return _executorConfig(executor); } function _executorConfig(IExecutor executor) internal view returns (ExecutorConfig storage config) { ExecutorStorage storage es; bytes32 slot = EXECUTOR_MANAGER_STORAGE_SLOT; assembly { es.slot := slot } config = es.executorConfig[executor]; } function _installExecutor(IExecutor executor, bytes calldata executorData, IHook hook) internal { _installExecutorWithoutInit(executor, hook); executor.onInstall(executorData); } function _installExecutorWithoutInit(IExecutor executor, IHook hook) internal { if (address(hook) == address(0)) { hook = IHook(address(1)); } ExecutorConfig storage config = _executorConfig(executor); config.hook = hook; emit IERC7579Account.ModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor)); } function _uninstallExecutor(IExecutor executor, bytes calldata executorData) internal returns (IHook hook) { ExecutorConfig storage config = _executorConfig(executor); hook = config.hook; config.hook = IHook(address(0)); ModuleLib.uninstallModule(address(executor), executorData); emit IERC7579Account.ModuleUninstalled(MODULE_TYPE_EXECUTOR, address(executor)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IHook, IFallback, IModule} from "../interfaces/IERC7579Modules.sol"; import {IERC7579Account} from "../interfaces/IERC7579Account.sol"; import {CallType} from "../utils/ExecLib.sol"; import { SELECTOR_MANAGER_STORAGE_SLOT, CALLTYPE_DELEGATECALL, CALLTYPE_SINGLE, MODULE_TYPE_FALLBACK } from "../types/Constants.sol"; import {ModuleLib} from "../utils/ModuleLib.sol"; abstract contract SelectorManager { error NotSupportedCallType(); struct SelectorConfig { IHook hook; // 20 bytes for hook address address target; // 20 bytes target will be fallback module, called with call CallType callType; } struct SelectorStorage { mapping(bytes4 => SelectorConfig) selectorConfig; } function selectorConfig(bytes4 selector) external view returns (SelectorConfig memory) { return _selectorConfig(selector); } function _selectorConfig(bytes4 selector) internal view returns (SelectorConfig storage config) { config = _selectorStorage().selectorConfig[selector]; } function _selectorStorage() internal pure returns (SelectorStorage storage ss) { bytes32 slot = SELECTOR_MANAGER_STORAGE_SLOT; assembly { ss.slot := slot } } function _installSelector(bytes4 selector, address target, IHook hook, bytes calldata selectorData) internal { if (address(hook) == address(0)) { hook = IHook(address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF)); } SelectorConfig storage ss = _selectorConfig(selector); // we are going to install only through call/delegatecall CallType callType = CallType.wrap(bytes1(selectorData[0])); if (callType == CALLTYPE_SINGLE) { IModule(target).onInstall(selectorData[1:]); emit IERC7579Account.ModuleInstalled(MODULE_TYPE_FALLBACK, target); } else if (callType != CALLTYPE_DELEGATECALL) { // NOTE : we are not going to call onInstall for delegatecall, and we support only CALL & DELEGATECALL revert NotSupportedCallType(); } ss.hook = hook; ss.target = target; ss.callType = callType; } function _uninstallSelector(bytes4 selector, bytes calldata selectorDeinitData) internal returns (IHook hook) { SelectorConfig storage ss = _selectorConfig(selector); hook = ss.hook; ss.hook = IHook(address(0)); if (ss.callType == CALLTYPE_SINGLE) { ModuleLib.uninstallModule(ss.target, selectorDeinitData); emit IERC7579Account.ModuleUninstalled(MODULE_TYPE_FALLBACK, ss.target); } ss.target = address(0); ss.callType = CallType.wrap(bytes1(0x00)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import {PackedUserOperation} from "./PackedUserOperation.sol"; interface IModule { error AlreadyInitialized(address smartAccount); error NotInitialized(address smartAccount); /** * @dev This function is called by the smart account during installation of the module * @param data arbitrary data that may be required on the module during `onInstall` * initialization * * MUST revert on error (i.e. if module is already enabled) */ function onInstall(bytes calldata data) external payable; /** * @dev This function is called by the smart account during uninstallation of the module * @param data arbitrary data that may be required on the module during `onUninstall` * de-initialization * * MUST revert on error */ function onUninstall(bytes calldata data) external payable; /** * @dev Returns boolean value if module is a certain type * @param moduleTypeId the module type ID according the ERC-7579 spec * * MUST return true if the module is of the given type and false otherwise */ function isModuleType(uint256 moduleTypeId) external view returns (bool); /** * @dev Returns if the module was already initialized for a provided smartaccount */ function isInitialized(address smartAccount) external view returns (bool); } interface IValidator is IModule { error InvalidTargetAddress(address target); /** * @dev Validates a transaction on behalf of the account. * This function is intended to be called by the MSA during the ERC-4337 validation phase * Note: solely relying on bytes32 hash and signature is not sufficient for some * validation implementations (i.e. SessionKeys often need access to userOp.calldata) * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata. * The MSA MUST clean up the userOp before sending it to the validator. * @param userOpHash The hash of the user operation to be validated * @return return value according to ERC-4337 */ function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external payable returns (uint256); /** * Validator can be used for ERC-1271 validation */ function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data) external view returns (bytes4); } interface IExecutor is IModule {} interface IHook is IModule { function preCheck(address msgSender, uint256 msgValue, bytes calldata msgData) external payable returns (bytes memory hookData); function postCheck(bytes calldata hookData) external payable; } interface IFallback is IModule {} interface IPolicy is IModule { function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp) external payable returns (uint256); function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig) external view returns (uint256); } interface ISigner is IModule { function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash) external payable returns (uint256); function checkSignature(bytes32 id, address sender, bytes32 hash, bytes calldata sig) external view returns (bytes4); }
// 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 pragma solidity ^0.8.23; import {ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload} from "../types/Types.sol"; import { CALLTYPE_SINGLE, CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, EXECTYPE_TRY, CALLTYPE_DELEGATECALL } from "../types/Constants.sol"; import {Execution} from "../types/Structs.sol"; /** * @dev ExecLib is a helper library for execution */ library ExecLib { error ExecutionFailed(); event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result); function execute(ExecMode execMode, bytes calldata executionCalldata) internal returns (bytes[] memory returnData) { (CallType callType, ExecType execType,,) = decode(execMode); // check if calltype is batch or single if (callType == CALLTYPE_BATCH) { // destructure executionCallData according to batched exec Execution[] calldata executions = decodeBatch(executionCalldata); // check if execType is revert or try if (execType == EXECTYPE_DEFAULT) returnData = execute(executions); else if (execType == EXECTYPE_TRY) returnData = tryExecute(executions); else revert("Unsupported"); } else if (callType == CALLTYPE_SINGLE) { // destructure executionCallData according to single exec (address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata); returnData = new bytes[](1); bool success; // check if execType is revert 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(0, returnData[0]); } else { revert("Unsupported"); } } else if (callType == CALLTYPE_DELEGATECALL) { returnData = new bytes[](1); address delegate = address(bytes20(executionCalldata[0:20])); bytes calldata callData = executionCalldata[20:]; bool success; (success, returnData[0]) = executeDelegatecall(delegate, callData); if (execType == EXECTYPE_TRY) { if (!success) emit TryExecuteUnsuccessful(0, returnData[0]); } else if (execType == EXECTYPE_DEFAULT) { if (!success) revert("Delegatecall failed"); } else { revert("Unsupported"); } } else { revert("Unsupported"); } } function execute(Execution[] calldata executions) internal returns (bytes[] memory result) { uint256 length = executions.length; result = new bytes[](length); for (uint256 i; i < length; i++) { Execution calldata _exec = executions[i]; result[i] = execute(_exec.target, _exec.value, _exec.callData); } } function tryExecute(Execution[] calldata executions) internal returns (bytes[] memory result) { uint256 length = executions.length; result = new bytes[](length); for (uint256 i; i < length; i++) { Execution calldata _exec = executions[i]; bool success; (success, result[i]) = tryExecute(_exec.target, _exec.value, _exec.callData); if (!success) emit TryExecuteUnsuccessful(i, result[i]); } } function execute(address target, uint256 value, bytes calldata callData) internal 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. } } function tryExecute(address target, uint256 value, bytes calldata callData) internal 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. } } /// @dev Execute a delegatecall with `delegate` on this account. function executeDelegatecall(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. } } function decode(ExecMode mode) internal pure returns (CallType _calltype, ExecType _execType, ExecModeSelector _modeSelector, ExecModePayload _modePayload) { assembly { _calltype := mode _execType := shl(8, mode) _modeSelector := shl(48, mode) _modePayload := shl(80, mode) } } function encode(CallType callType, ExecType execType, ExecModeSelector mode, ExecModePayload payload) internal pure returns (ExecMode) { return ExecMode.wrap( bytes32(abi.encodePacked(callType, execType, bytes4(0), ExecModeSelector.unwrap(mode), payload)) ); } function encodeSimpleBatch() internal pure returns (ExecMode mode) { mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00)); } function encodeSimpleSingle() internal pure returns (ExecMode mode) { mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00)); } function getCallType(ExecMode mode) internal pure returns (CallType calltype) { assembly { calltype := mode } } function decodeBatch(bytes calldata callData) internal pure 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[]) */ // solhint-disable-next-line no-inline-assembly 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 encodeSingle(address target, uint256 value, bytes memory callData) internal pure returns (bytes memory userOpCalldata) { userOpCalldata = abi.encodePacked(target, value, callData); } function doFallback2771Static(address fallbackHandler) internal view returns (bool success, bytes memory result) { assembly { function allocate(length) -> pos { pos := mload(0x40) mstore(0x40, add(pos, length)) } let calldataPtr := allocate(calldatasize()) calldatacopy(calldataPtr, 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(20) mstore(senderPtr, shl(96, caller())) // Add 20 bytes for the address appended add the end success := staticcall(gas(), fallbackHandler, calldataPtr, add(calldatasize(), 20), 0, 0) result := mload(0x40) 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. } } function doFallback2771Call(address target) internal returns (bool success, bytes memory result) { assembly { function allocate(length) -> pos { pos := mload(0x40) mstore(0x40, add(pos, length)) } let calldataPtr := allocate(calldatasize()) calldatacopy(calldataPtr, 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(20) mstore(senderPtr, shl(96, caller())) // Add 20 bytes for the address appended add the end success := call(gas(), target, 0, calldataPtr, add(calldatasize(), 20), 0, 0) result := mload(0x40) 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. } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {CallType, ExecType, ExecModeSelector} from "./Types.sol"; import {PassFlag, ValidationMode, ValidationType} from "./Types.sol"; import {ValidationData} from "./Types.sol"; // --- ERC7579 calltypes --- // 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); // --- ERC7579 exectypes --- // @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); // --- ERC7579 mode selector --- ExecModeSelector constant EXEC_MODE_DEFAULT = ExecModeSelector.wrap(bytes4(0x00000000)); // --- Kernel permission skip flags --- PassFlag constant SKIP_USEROP = PassFlag.wrap(0x0001); PassFlag constant SKIP_SIGNATURE = PassFlag.wrap(0x0002); // --- Kernel validation modes --- ValidationMode constant VALIDATION_MODE_DEFAULT = ValidationMode.wrap(0x00); ValidationMode constant VALIDATION_MODE_ENABLE = ValidationMode.wrap(0x01); ValidationMode constant VALIDATION_MODE_INSTALL = ValidationMode.wrap(0x02); // --- Kernel validation types --- ValidationType constant VALIDATION_TYPE_ROOT = ValidationType.wrap(0x00); ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01); ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02); // --- storage slots --- // bytes32(uint256(keccak256('kernel.v3.selector')) - 1) bytes32 constant SELECTOR_MANAGER_STORAGE_SLOT = 0x7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b; // bytes32(uint256(keccak256('kernel.v3.executor')) - 1) bytes32 constant EXECUTOR_MANAGER_STORAGE_SLOT = 0x1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b86; // bytes32(uint256(keccak256('kernel.v3.hook')) - 1) bytes32 constant HOOK_MANAGER_STORAGE_SLOT = 0x4605d5f70bb605094b2e761eccdc27bed9a362d8612792676bf3fb9b12832ffc; // bytes32(uint256(keccak256('kernel.v3.validation')) - 1) bytes32 constant VALIDATION_MANAGER_STORAGE_SLOT = 0x7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f; bytes32 constant ERC1967_IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; // --- Kernel validation nonce incremental size limit --- uint32 constant MAX_NONCE_INCREMENT_SIZE = 10; // -- EIP712 type hash --- bytes32 constant ENABLE_TYPE_HASH = 0xb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c505; bytes32 constant KERNEL_WRAPPER_TYPE_HASH = 0x1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83; // --- ERC constants --- // ERC4337 constants uint256 constant SIG_VALIDATION_FAILED_UINT = 1; uint256 constant SIG_VALIDATION_SUCCESS_UINT = 0; ValidationData constant SIG_VALIDATION_FAILED = ValidationData.wrap(SIG_VALIDATION_FAILED_UINT); // ERC-1271 constants bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e; bytes4 constant ERC1271_INVALID = 0xffffffff; uint256 constant MODULE_TYPE_VALIDATOR = 1; uint256 constant MODULE_TYPE_EXECUTOR = 2; uint256 constant MODULE_TYPE_FALLBACK = 3; uint256 constant MODULE_TYPE_HOOK = 4; uint256 constant MODULE_TYPE_POLICY = 5; uint256 constant MODULE_TYPE_SIGNER = 6;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; // Custom type for improved developer experience type ExecMode is bytes32; type CallType is bytes1; type ExecType is bytes1; type ExecModeSelector is bytes4; type ExecModePayload is bytes22; using {eqModeSelector as ==} for ExecModeSelector global; using {eqCallType as ==} for CallType global; using {notEqCallType 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 notEqCallType(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); } function eqModeSelector(ExecModeSelector a, ExecModeSelector b) pure returns (bool) { return ExecModeSelector.unwrap(a) == ExecModeSelector.unwrap(b); } type ValidationMode is bytes1; type ValidationId is bytes21; type ValidationType is bytes1; type PermissionId is bytes4; type PolicyData is bytes22; // 2bytes for flag on skip, 20 bytes for validator address type PassFlag is bytes2; using {vModeEqual as ==} for ValidationMode global; using {vTypeEqual as ==} for ValidationType global; using {vIdentifierEqual as ==} for ValidationId global; using {vModeNotEqual as !=} for ValidationMode global; using {vTypeNotEqual as !=} for ValidationType global; using {vIdentifierNotEqual as !=} for ValidationId global; // nonce = uint192(key) + nonce // key = mode + (vtype + validationDataWithoutType) + 2bytes parallelNonceKey // key = 0x00 + 0x00 + 0x000 .. 00 + 0x0000 // key = 0x00 + 0x01 + 0x1234...ff + 0x0000 // key = 0x00 + 0x02 + ( ) + 0x000 function vModeEqual(ValidationMode a, ValidationMode b) pure returns (bool) { return ValidationMode.unwrap(a) == ValidationMode.unwrap(b); } function vModeNotEqual(ValidationMode a, ValidationMode b) pure returns (bool) { return ValidationMode.unwrap(a) != ValidationMode.unwrap(b); } function vTypeEqual(ValidationType a, ValidationType b) pure returns (bool) { return ValidationType.unwrap(a) == ValidationType.unwrap(b); } function vTypeNotEqual(ValidationType a, ValidationType b) pure returns (bool) { return ValidationType.unwrap(a) != ValidationType.unwrap(b); } function vIdentifierEqual(ValidationId a, ValidationId b) pure returns (bool) { return ValidationId.unwrap(a) == ValidationId.unwrap(b); } function vIdentifierNotEqual(ValidationId a, ValidationId b) pure returns (bool) { return ValidationId.unwrap(a) != ValidationId.unwrap(b); } type ValidationData is uint256; type ValidAfter is uint48; type ValidUntil is uint48; function getValidationResult(ValidationData validationData) pure returns (address result) { assembly { result := validationData } } function packValidationData(ValidAfter validAfter, ValidUntil validUntil) pure returns (uint256) { return uint256(ValidAfter.unwrap(validAfter)) << 208 | uint256(ValidUntil.unwrap(validUntil)) << 160; } function parseValidationData(uint256 validationData) pure returns (ValidAfter validAfter, ValidUntil validUntil, address result) { assembly { result := validationData validUntil := and(shr(160, validationData), 0xffffffffffff) switch iszero(validUntil) case 1 { validUntil := 0xffffffffffff } validAfter := shr(208, validationData) } }
// 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 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.0; import {IValidator, IPolicy} from "../interfaces/IERC7579Modules.sol"; import {PassFlag, ValidationType, ValidationId, ValidationMode, PolicyData, PermissionId} from "../types/Types.sol"; import {VALIDATION_TYPE_PERMISSION} from "../types/Constants.sol"; library ValidatorLib { function encodeFlag(bool skipUserOp, bool skipSignature) internal pure returns (PassFlag flag) { assembly { if skipUserOp { flag := 0x0001000000000000000000000000000000000000000000000000000000000000 } if skipSignature { flag := or(flag, 0x0002000000000000000000000000000000000000000000000000000000000000) } } } function encodePolicyData(bool skipUserOp, bool skipSig, address policy) internal pure returns (PolicyData data) { assembly { if skipUserOp { data := 0x0001000000000000000000000000000000000000000000000000000000000000 } if skipSig { data := or(data, 0x0002000000000000000000000000000000000000000000000000000000000000) } data := or(data, shl(80, policy)) } } function encodePermissionAsNonce(bytes1 mode, bytes4 permissionId, uint16 nonceKey, uint64 nonce) internal pure returns (uint256 res) { return encodeAsNonce( mode, ValidationType.unwrap(VALIDATION_TYPE_PERMISSION), bytes20(permissionId), nonceKey, nonce ); } function encodeAsNonce(bytes1 mode, bytes1 vType, bytes20 ValidationIdWithoutType, uint16 nonceKey, uint64 nonce) internal pure returns (uint256 res) { assembly { res := nonce res := or(res, shl(64, nonceKey)) res := or(res, shr(16, ValidationIdWithoutType)) res := or(res, shr(8, vType)) res := or(res, mode) } } function encodeAsNonceKey(bytes1 mode, bytes1 vType, bytes20 ValidationIdWithoutType, uint16 nonceKey) internal pure returns (uint192 res) { assembly { res := or(nonceKey, shr(80, ValidationIdWithoutType)) res := or(res, shr(72, vType)) res := or(res, shr(64, mode)) } } function decodeNonce(uint256 nonce) internal pure returns (ValidationMode mode, ValidationType vType, ValidationId identifier) { // 2bytes mode (1byte currentMode, 1byte type) // 21bytes identifier // 1byte mode | 1byte type | 20bytes identifierWithoutType | 2byte nonceKey | 8byte nonce == 32bytes assembly { mode := nonce vType := shl(8, nonce) identifier := shl(8, nonce) switch shr(248, identifier) case 0x0000000000000000000000000000000000000000000000000000000000000002 { identifier := and(identifier, 0xffffffffff000000000000000000000000000000000000000000000000000000) } } } function decodeSignature(bytes calldata signature) internal pure returns (ValidationId vId, bytes calldata sig) { assembly { vId := calldataload(signature.offset) switch shr(248, vId) case 0 { // sudo mode vId := 0x00 sig.offset := add(signature.offset, 1) sig.length := sub(signature.length, 1) } case 1 { // validator mode sig.offset := add(signature.offset, 21) sig.length := sub(signature.length, 21) } case 2 { vId := and(vId, 0xffffffffff000000000000000000000000000000000000000000000000000000) sig.offset := add(signature.offset, 5) sig.length := sub(signature.length, 5) } default { revert(0x00, 0x00) } } } function decodePolicyData(PolicyData data) internal pure returns (PassFlag flag, IPolicy policy) { assembly { flag := data policy := shr(80, data) } } function validatorToIdentifier(IValidator validator) internal pure returns (ValidationId vId) { assembly { vId := 0x0100000000000000000000000000000000000000000000000000000000000000 vId := or(vId, shl(88, validator)) } } function getType(ValidationId validator) internal pure returns (ValidationType vType) { assembly { vType := validator } } function getValidator(ValidationId validator) internal pure returns (IValidator v) { assembly { v := shr(88, validator) } } function getPermissionId(ValidationId validator) internal pure returns (PermissionId id) { assembly { id := shl(8, validator) } } function permissionToIdentifier(PermissionId permissionId) internal pure returns (ValidationId vId) { assembly { vId := 0x0200000000000000000000000000000000000000000000000000000000000000 vId := or(vId, shr(8, permissionId)) } } function getPolicy(PolicyData data) internal pure returns (IPolicy vId) { assembly { vId := shr(80, data) } } function getPermissionSkip(PolicyData data) internal pure returns (PassFlag flag) { assembly { flag := data } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {SIG_VALIDATION_FAILED_UINT} from "../types/Constants.sol"; import {ValidationData, getValidationResult} from "../types/Types.sol"; function _intersectValidationData(ValidationData a, ValidationData b) pure returns (ValidationData validationData) { assembly { // xor(a,b) == shows only matching bits // and(xor(a,b), 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff) == filters out the validAfter and validUntil bits // if the result is not zero, then aggregator part is not matching // validCase : // a == 0 || b == 0 || xor(a,b) == 0 // invalidCase : // a mul b != 0 && xor(a,b) != 0 let sum := shl(96, add(a, b)) switch or( iszero(and(xor(a, b), 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff)), or(eq(sum, shl(96, a)), eq(sum, shl(96, b))) ) case 1 { validationData := and(or(a, b), 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff) // validAfter let a_vd := and(0xffffffffffff0000000000000000000000000000000000000000000000000000, a) let b_vd := and(0xffffffffffff0000000000000000000000000000000000000000000000000000, b) validationData := or(validationData, xor(a_vd, mul(xor(a_vd, b_vd), gt(b_vd, a_vd)))) // validUntil a_vd := and(0x000000000000ffffffffffff0000000000000000000000000000000000000000, a) if iszero(a_vd) { a_vd := 0x000000000000ffffffffffff0000000000000000000000000000000000000000 } b_vd := and(0x000000000000ffffffffffff0000000000000000000000000000000000000000, b) if iszero(b_vd) { b_vd := 0x000000000000ffffffffffff0000000000000000000000000000000000000000 } let until := xor(a_vd, mul(xor(a_vd, b_vd), lt(b_vd, a_vd))) if iszero(until) { until := 0x000000000000ffffffffffff0000000000000000000000000000000000000000 } validationData := or(validationData, until) } default { validationData := SIG_VALIDATION_FAILED_UINT } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; struct Execution { address target; uint256 value; bytes callData; }
{ "remappings": [ "ExcessivelySafeCall/=lib/ExcessivelySafeCall/src/", "forge-std/=lib/forge-std/src/", "solady/=lib/solady/src/", "ds-test/=lib/forge-std/lib/ds-test/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": {} }
[{"inputs":[{"internalType":"contract IEntryPoint","name":"_entrypoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EnableNotApproved","type":"error"},{"inputs":[],"name":"ExecutionReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"InitConfigError","type":"error"},{"inputs":[],"name":"InvalidCallType","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidExecutor","type":"error"},{"inputs":[],"name":"InvalidFallback","type":"error"},{"inputs":[],"name":"InvalidMode","type":"error"},{"inputs":[],"name":"InvalidModuleType","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSelector","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidValidationType","type":"error"},{"inputs":[],"name":"InvalidValidator","type":"error"},{"inputs":[],"name":"NonceInvalidationError","type":"error"},{"inputs":[],"name":"NotSupportedCallType","type":"error"},{"inputs":[],"name":"OnlyExecuteUserOp","type":"error"},{"inputs":[],"name":"PermissionDataLengthMismatch","type":"error"},{"inputs":[],"name":"PermissionNotAlllowedForSignature","type":"error"},{"inputs":[],"name":"PermissionNotAlllowedForUserOp","type":"error"},{"inputs":[],"name":"PolicyDataTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"PolicyFailed","type":"error"},{"inputs":[],"name":"PolicySignatureOrderError","type":"error"},{"inputs":[],"name":"RootValidatorCannotBeRemoved","type":"error"},{"inputs":[],"name":"SignerPrefixNotPresent","type":"error"},{"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":"address","name":"module","type":"address"},{"indexed":false,"internalType":"bool","name":"result","type":"bool"}],"name":"ModuleUninstallResult","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":"uint32","name":"nonce","type":"uint32"}],"name":"NonceInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"PermissionId","name":"permission","type":"bytes4"},{"indexed":false,"internalType":"uint32","name":"nonce","type":"uint32"}],"name":"PermissionInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"PermissionId","name":"permission","type":"bytes4"}],"name":"PermissionUninstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"ValidationId","name":"rootValidator","type":"bytes21"}],"name":"RootValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"ValidationId","name":"vId","type":"bytes21"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"SelectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"batchExecutionindex","type":"uint256"},{"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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IValidator","name":"validator","type":"address"},{"indexed":false,"internalType":"uint32","name":"nonce","type":"uint32"}],"name":"ValidatorInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IValidator","name":"validator","type":"address"}],"name":"ValidatorUninstalled","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"accountId","outputs":[{"internalType":"string","name":"accountImplementationId","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"_rootValidator","type":"bytes21"},{"internalType":"contract IHook","name":"hook","type":"address"},{"internalType":"bytes","name":"validatorData","type":"bytes"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"name":"changeRootValidator","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentNonce","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":[],"name":"entrypoint","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ExecMode","name":"execMode","type":"bytes32"},{"internalType":"bytes","name":"executionCalldata","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ExecMode","name":"execMode","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":"userOpHash","type":"bytes32"}],"name":"executeUserOp","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IExecutor","name":"executor","type":"address"}],"name":"executorConfig","outputs":[{"components":[{"internalType":"contract IHook","name":"hook","type":"address"}],"internalType":"struct ExecutorManager.ExecutorConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"_rootValidator","type":"bytes21"},{"internalType":"contract IHook","name":"hook","type":"address"},{"internalType":"bytes","name":"validatorData","type":"bytes"},{"internalType":"bytes","name":"hookData","type":"bytes"},{"internalType":"bytes[]","name":"initConfig","type":"bytes[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"initData","type":"bytes"}],"name":"installModule","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId[]","name":"vIds","type":"bytes21[]"},{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"contract IHook","name":"hook","type":"address"}],"internalType":"struct ValidationManager.ValidationConfig[]","name":"configs","type":"tuple[]"},{"internalType":"bytes[]","name":"validationData","type":"bytes[]"},{"internalType":"bytes[]","name":"hookData","type":"bytes[]"}],"name":"installValidations","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"nonce","type":"uint32"}],"name":"invalidateNonce","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"vId","type":"bytes21"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"isAllowedSelector","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleType","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":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"PermissionId","name":"pId","type":"bytes4"}],"name":"permissionConfig","outputs":[{"components":[{"internalType":"PassFlag","name":"permissionFlag","type":"bytes2"},{"internalType":"contract ISigner","name":"signer","type":"address"},{"internalType":"PolicyData[]","name":"policyData","type":"bytes22[]"}],"internalType":"struct ValidationManager.PermissionConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootValidator","outputs":[{"internalType":"ValidationId","name":"","type":"bytes21"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"selectorConfig","outputs":[{"components":[{"internalType":"contract IHook","name":"hook","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"CallType","name":"callType","type":"bytes1"}],"internalType":"struct SelectorManager.SelectorConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ExecMode","name":"mode","type":"bytes32"}],"name":"supportsExecutionMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"supportsModule","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"deInitData","type":"bytes"}],"name":"uninstallModule","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"vId","type":"bytes21"},{"internalType":"bytes","name":"deinitData","type":"bytes"},{"internalType":"bytes","name":"hookDeinitData","type":"bytes"}],"name":"uninstallValidation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"validNonceFrom","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"missingAccountFunds","type":"uint256"}],"name":"validateUserOp","outputs":[{"internalType":"ValidationData","name":"validationData","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"vId","type":"bytes21"}],"name":"validationConfig","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"contract IHook","name":"hook","type":"address"}],"internalType":"struct ValidationManager.ValidationConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101403461020457601f615b3b38819003918201601f191683019291906001600160401b0384118385101761020957816020928492604096875283398101031261020457516001600160a01b038116810361020457306080524660a05260a082516100698161021f565b600681526005602082016512d95c9b995b60d21b81526020865161008c8161021f565b838152019264302e332e3160d81b845251902091208160c0528060e0528451917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f835260208301528482015246606082015230608082015220916101009283526101209182528051602081019063deadbeef60e01b8252600481526101108161021f565b5190516001600160581b0319918282169190601581106101ef575b505090507f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f9060581c60018060a81b03198254161790555190615900928361023b84396080518361455a015260a0518361457d015260c051836145ef015260e05183614615015251826145390152518181816103af015281816106d30152818161088901528181610c22015281816110020152818161132901528181611491015281816114f101528181611a1901528181611b5f0152818161259d0152612f0d0152f35b8391925060150360031b1b161680388061012b565b600080fd5b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b038211176102095760405256fe6080604052600436101561001d575b36612dc85761001b612d97565b005b60003560e01c8063112d3a7d146101fd578063150b7a02146101f85780631626ba7e146101f357806319822f7c146101ee5780631f1b92e3146101e95780633659cfe6146101e45780633c3b752b146101df57806352141cd9146101da57806357b3a5f4146101d55780636e6fa0c6146101d0578063721e67f4146101cb57806384b0196e146101c65780638dd7712f146101c157806390ef8862146101bc5780639198bdf5146101b75780639517e29f146101b25780639cfd7cff146101ad578063a65d69d4146101a8578063a71763a8146101a3578063adb610a31461019e578063b8afe17d14610199578063bc197c8114610194578063c3e589781461018f578063d03c79141461018a578063d691c96414610185578063e6f3d50a14610180578063e9ae5c531461017b578063f1f7f0f914610176578063f23a6e61146101715763f2dc691d0361000e57611cec565b611c92565b611c5a565b611b2e565b61199e565b6118ba565b61186d565b611791565b61168a565b611620565b6115ec565b6114c0565b61147b565b611424565b6112f8565b6111f1565b6110d0565b610fcc565b610f2a565b610e7e565b610e21565b610d73565b610b99565b6109c2565b610849565b610691565b610371565b610311565b6102b7565b610291565b6001600160a01b0381160361021357565b600080fd5b359061022382610202565b565b9181601f84011215610213578235916001600160401b038311610213576020838186019501011161021357565b6060600319820112610213576004359160243561026e81610202565b91604435906001600160401b0382116102135761028d91600401610225565b9091565b346102135760206102ad6102a436610252565b92919091611eec565b6040519015158152f35b34610213576080366003190112610213576102d3600435610202565b6102de602435610202565b6064356001600160401b038111610213576102fd903690600401610225565b5050604051630a85bd0160e11b8152602090f35b34610213576040366003190112610213576024356001600160401b0381116102135761034f6103466020923690600401610225565b9060043561209c565b6040516001600160e01b03199091168152f35b90816101209103126102135790565b606036600319011261021357600480356001600160401b0381116102135761039c9036908301610362565b60243590604435906001600160a01b03907f00000000000000000000000000000000000000000000000000000000000000008216330361065c578084926103e66020830135613115565b6001600160f81b031990911615959093909186610632575b908461040a93926132fa565b9561041c61041784611e7a565b6121db565b94159485806105f0575b6105df57602001516001600160a01b03169182169081156105ce5760019261045b61047a926000526000602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b0361052d57826104cf575b50506104be576104a89250805b6104ac575b506040519081529081906020820190565b0390f35b3490349034903490335af15038610497565b604051631a0a9b9f60e21b81528390fd5b6105269250610522916105046104fe6104f86104ed61051b95611eb3565b936060810190612207565b90611d1b565b90611e4e565b63ffffffff60e01b16600052602052604060002090565b5460ff1690565b1590565b3880610485565b8291929161059b575b5061058a576104f881606061054c930190612207565b638dd7712f60e01b916001600160e01b03199161056891611e4e565b1603610579576104a8925080610492565b60405163dbbb044b60e01b81528390fd5b604051631a0a9b9f60e21b81528490fd5b6105c8915061051b6105af61052292611eb3565b6105046104fe6105c26060880188612207565b90611d0a565b38610536565b604051631a0a9b9f60e21b81528990fd5b604051633ab3447f60e11b81528990fd5b50805163ffffffff1663ffffffff61062a6106216000805160206158e08339815191525463ffffffff9060c81c1690565b63ffffffff1690565b911610610426565b93509061040a916106526000805160206158e08339815191525460581b90565b94909192506103fe565b6040516348f5c3ed60e01b81528590fd5b6004359063ffffffff8216820361021357565b359063ffffffff8216820361021357565b6020366003190112610213576106a561066d565b6106c76106c16000805160206158e08339815191525460581b90565b60581c90565b6001600160a01b0390337f0000000000000000000000000000000000000000000000000000000000000000831614158061083f575b156108345760405163ecd0596160e01b8152600480820152911690602081602481855afa9081156107c557600091610805575b50156107f35760405163d68f602560e01b81529160008380610756363433600485016122ca565b038183865af19283156107c5576000936107ca575b50610775906134a1565b803b1561021357604051630b9dfbed60e11b81529160009183918290849082906107a29060048301612306565b03925af180156107c5576107b257005b806107bf61001b9261111a565b80610ed7565b612090565b6107759193506107ec903d806000833e6107e4818361119f565b81019061226c565b929061076b565b6040516348f5c3ed60e01b8152600490fd5b610827915060203d60201161082d575b61081f818361119f565b810190612239565b3861072f565b503d610815565b505061001b906134a1565b50303314156106fc565b60203660031901126102135760043561086181610202565b61087d6106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580610976575b1561096b5760405163ecd0596160e01b8152600480820152911690602081602481855afa9081156107c55760009161094c575b50156107f35760405163d68f602560e01b8152916000838061090c363433600485016122ca565b038183865af19283156107c55760009361092b575b5061077590612317565b610775919350610945903d806000833e6107e4818361119f565b9290610921565b610965915060203d60201161082d5761081f818361119f565b386108e5565b505061001b90612317565b50303314156108b2565b6001600160581b031981160361021357565b9181601f84011215610213578235916001600160401b038311610213576020808501948460051b01011161021357565b346102135760a03660031901126102135760048035906109e182610980565b602435906109ee82610202565b6001600160401b0360443581811161021357610a0d9036908401610225565b909160643581811161021357610a269036908601610225565b92909160843590811161021357610a409036908701610992565b9490966001600160581b0319610a8081610a79610a6c6000805160206158e08339815191525460581b90565b6001600160581b03191690565b161561236b565b891615610b88576001600160f81b03198916600160f81b8114159081610b79575b50610b685788610ab6610b049798999a61356a565b610ad7610ac16111c0565b60018152925b6001600160a01b03166020840152565b6000805160206158e0833981519152805463ffffffff60a81b1916600160a81b1790556135c5565b6135c5565b60005b818110610b1057005b600080610b1e8385886123f5565b60409391610b30855180938193612411565b039082305af1610b3e612432565b5015610b4d5750600101610b07565b51636534eae560e11b81528084019182529081906020010390fd5b6040516361c4e91b60e11b81528790fd5b600160f91b1415905038610aa1565b604051631a0a9b9f60e21b81528790fd5b6080366003190112610213576004803590610bb382610980565b60243591610bc083610202565b6001600160401b039260443584811161021357610be09036908501610225565b909460643590811161021357610bf99036908601610225565b91610c166106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580610d57575b15610d4657169660405163ecd0596160e01b815260208180610c748b8201906004602083019252565b03818c5afa9081156107c557600091610d27575b5015610d165760405163d68f602560e01b81529460008680610cae3634338e85016122ca565b0381838d5af19586156107c557600096610cf7575b50610cce9596612462565b823b15610213576107a29260009283604051809681958294630b9dfbed60e11b84528301612306565b610cce9650610d10903d806000833e6107e4818361119f565b95610cc3565b6040516348f5c3ed60e01b81528790fd5b610d40915060203d60201161082d5761081f818361119f565b38610c88565b505092909361001b96929550612462565b5030331415610c4b565b6001600160e01b031981160361021357565b34610213576020366003190112610213576104a8610db5600435610d9681610d61565b600060408051610da581611132565b8281528260208201520152611fc3565b60405190610dc282611132565b80546001600160a01b0390811680845260019092015480821660208086019182526001600160f81b031960589390931b831660409687019081528651958652915190931692840192909252905116918101919091529081906060820190565b3461021357604036600319011261021357602060ff610e72600435610e4581610980565b610e5a60243591610e5583610d61565b611eb3565b9063ffffffff60e01b16600052602052604060002090565b54166040519015158152f35b34610213576020366003190112610213576020610eb4600435610ea081610202565b6000604051610eae8161114d565b52612f61565b60405190610ec18261114d565b546001600160a01b031690819052604051908152f35b600091031261021357565b60005b838110610ef55750506000910152565b8181015183820152602001610ee5565b90602091610f1e81518092818552858086019101610ee2565b601f01601f1916010190565b3461021357600036600319011261021357610f79610f466137d7565b90604051928392600f60f81b8452610f6b60209360e0602087015260e0860190610f05565b908482036040860152610f05565b90466060840152306080840152600060a084015282820360c0840152602060605192838152019160809160005b828110610fb557505050500390f35b835185528695509381019392810192600101610fa6565b6040366003190112610213576004356001600160401b03811161021357610ff7903690600401610362565b6001600160a01b03907f0000000000000000000000000000000000000000000000000000000000000000821633036107f357602435600090815260208190526040902054606091906001906001600160a01b0316938416141590816110a0575b61107261106b826060611079940190612207565b8091611d29565b903061391e565b501561108e5761108557005b61001b91613945565b60405163f21e646b60e01b8152600490fd5b915061107961107261106b6110c66110be61106b6060880188612207565b90348961389c565b9492505050611057565b3461021357600036600319011261021357602063ffffffff6000805160206158e08339815191525460c81c16604051908152f35b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161112d57604052565b611104565b606081019081106001600160401b0382111761112d57604052565b602081019081106001600160401b0382111761112d57604052565b604081019081106001600160401b0382111761112d57604052565b61012081019081106001600160401b0382111761112d57604052565b90601f801991011681019081106001600160401b0382111761112d57604052565b6040519061022382611168565b6040519061022382611183565b6001600160401b03811161112d5760051b60200190565b6080366003190112610213576001600160401b036004358181116102135761121d903690600401610992565b906024358381116102135736602382011215610213578060040135611241816111da565b91604091611252604051948561119f565b8084526020906024602086019160061b8401019236841161021357602401905b8382106112ba57505050505060443584811161021357611296903690600401610992565b91606435958611610213576112b261001b963690600401610992565b95909461256e565b84823603126102135782859182516112d181611168565b6112da85610680565b8152828501356112e981610202565b83820152815201910190611272565b61130136610252565b61131d6106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000000000000000000000000000000000000831614158061141a575b1561140e5760405163ecd0596160e01b815260048082015291169290602081602481875afa9081156107c5576000916113ef575b50156107f35760405163d68f602560e01b815293600085806113ad363433600485016122ca565b038183885af19485156107c5576000956113ce575b5061077593949561272a565b6107759495506113e8903d806000833e6107e4818361119f565b94936113c2565b611408915060203d60201161082d5761081f818361119f565b38611386565b50509161001b9361272a565b5030331415611352565b34610213576000366003190112610213576104a860405161144481611168565b60168152756b65726e656c2e616476616e6365642e76302e332e3160501b6020820152604051918291602083526020830190610f05565b34610213576000366003190112610213576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b6114c936610252565b6114e56106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f000000000000000000000000000000000000000000000000000000000000000083161415806115e2575b156115d65760405163ecd0596160e01b815260048082015291169290602081602481875afa9081156107c5576000916115b7575b50156107f35760405163d68f602560e01b81529360008580611575363433600485016122ca565b038183885af19485156107c557600095611596575b50610775939495612ad9565b6107759495506115b0903d806000833e6107e4818361119f565b949361158a565b6115d0915060203d60201161082d5761081f818361119f565b3861154e565b50509161001b93612ad9565b503033141561151a565b3461021357600036600319011261021357602063ffffffff6000805160206158e08339815191525460a81c16604051908152f35b3461021357602036600319011261021357604061165060043561164281610980565b61164a612c8f565b50611e7a565b602082519161165e83611168565b5463ffffffff81169283815260018060a01b03928391019160201c168152835192835251166020820152f35b346102135760a0366003190112610213576116a6600435610202565b6116b1602435610202565b6001600160401b03604435818111610213576116d1903690600401610992565b5050606435818111610213576116eb903690600401610992565b505060843590811161021357611705903690600401610225565b505060405163bc197c8160e01b8152602090f35b602080825282516001600160f01b03191681830152808301516001600160a01b03166040808401919091529092015160608083015280516080830181905260a090920192908101919060005b828110611773575050505090565b83516001600160501b03191685529381019392810192600101611765565b3461021357602080600319360112610213576004356117af81610d61565b6117d460409160608380516117c381611132565b600081526000878201520152611ffb565b908051916117e183611132565b805460f081901b6001600160f01b031916845260101c6001600160a01b031684840152815160019182018054808352600091825286822083880197939490939092905b82821061184b576104a888888861183d818e038261119f565b818301525191829182611719565b845460501b6001600160501b0319168952978801979383019390830190611824565b346102135760203660031901126102135760206102ad600435612ca8565b9060406003198301126102135760043591602435906001600160401b0382116102135761028d91600401610225565b6118c33661188b565b916001600160a01b036118d533612f61565b541690811561198c57606060019460018414159485611975575b6118f99293614147565b92611965575b5050906040519060208083016020845284518091526040840191602060408360051b8701019601926000905b8382106119385786880387f35b90919293948380611954839a603f198b82030186528951610f05565b99970195949391909101910161192b565b61196e91613945565b38806118ff565b6118f99250611985363487613818565b92506118ef565b60405163710c949760e01b8152600490fd5b60603660031901126102135760048035906119b882610980565b6001600160401b0391602435838111610213576119d89036908401610225565b93604435908111610213576119f09036908501610225565b90611a0d6106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580611b24575b15611b1457169560405163ecd0596160e01b815260208180611a6b8a8201906004602083019252565b03818b5afa9081156107c557600091611af5575b5015611ae45760405163d68f602560e01b81529360008580611aa53634338d85016122ca565b0381838c5af19485156107c557600095611ac5575b50610cce9495612d6a565b610cce9550611ade903d806000833e6107e4818361119f565b94611aba565b6040516348f5c3ed60e01b81528690fd5b611b0e915060203d60201161082d5761081f818361119f565b38611a7f565b50509261001b9592919450612d6a565b5030331415611a42565b611b373661188b565b611b536106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580611c50575b15611c445760405163ecd0596160e01b815260048082015291169190602081602481865afa9081156107c557600091611c25575b50156107f35760405163d68f602560e01b81529260008480611be3363433600485016122ca565b038183875af19384156107c557600094611c04575b50610775929394612d7f565b610775939450611c1e903d806000833e6107e4818361119f565b9392611bf8565b611c3e915060203d60201161082d5761081f818361119f565b38611bbc565b50509061001b92612d7f565b5030331415611b88565b346102135760003660031901126102135760206000805160206158e08339815191525460581b604051906001600160581b0319168152f35b346102135760a036600319011261021357611cae600435610202565b611cb9602435610202565b6084356001600160401b03811161021357611cd8903690600401610225565b505060405163f23a6e6160e01b8152602090f35b346102135760203660031901126102135760206102ad600435612d8a565b906008116102135760040190600490565b906004116102135790600490565b909291928360041161021357831161021357600401916003190190565b906018116102135760040190601490565b906014116102135790601490565b906020116102135790602090565b909291928360011161021357831161021357600101916000190190565b909291928360141161021357831161021357601401916013190190565b906009116102135760010190600890565b909291928360091161021357831161021357600901916008190190565b906016116102135790601690565b906016116102135760020190601490565b909291928360161161021357831161021357601601916015190190565b906002116102135790600290565b90602c116102135760180190601490565b90939293848311610213578411610213578101920390565b6001600160e01b03199035818116939260048110611e6b57505050565b60040360031b82901b16169150565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f850602052604060002090565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f851602052604060002090565b90929060018103611f3b57506001600160a01b0392611f359250611f25915060581b600160581b600160f81b0316600160f81b17611e7a565b5460201c6001600160a01b031690565b16151590565b60028103611f7b57506001600160a01b0392611f359250611f6f9150611f62908416612f61565b546001600160a01b031690565b6001600160a01b031690565b600303611fbb57611f9c611f976104fe600193611faa95611d1b565b611fc3565b01546001600160a01b031690565b6001600160a01b0390811691161490565b505050600090565b63ffffffff60e01b166000527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b602052604060002090565b63ffffffff60e01b166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f852602052604060002090565b90816020910312610213575161204881610d61565b90565b908060209392818452848401376000828201840152601f01601f1916010190565b612048949260609260018060a01b031682526020820152816040820152019161204b565b6040513d6000823e3d90fd5b916120a691612f9a565b91906001600160f81b0319808316156121ba575b6001600160a01b0390816120d3611f6f611f2587611e7a565b16156121a8578316600160f81b03612158579060209392916120f7612115966130cc565b604051637aa8f17760e11b815296879586948593336004860161206c565b039260581c165afa9081156107c55760009161212f575090565b612048915060203d602011612151575b612149818361119f565b810190612033565b503d61213f565b509060081b92600160f11b61218661217961217287611ffb565b5460f01b90565b6001600160f01b03191690565b166121965761204893339061301b565b604051635b71057960e01b8152600490fd5b604051631a0a9b9f60e21b8152600490fd5b91506121d56000805160206158e08339815191525460581b90565b916120ba565b906040516121e881611168565b915463ffffffff81168352602090811c6001600160a01b031690830152565b903590601e198136030182121561021357018035906001600160401b0382116102135760200191813603831361021357565b90816020910312610213575180151581036102135790565b6001600160401b03811161112d57601f01601f191660200190565b602081830312610213578051906001600160401b038211610213570181601f8201121561021357805161229e81612251565b926122ac604051948561119f565b81845260208284010111610213576120489160208085019101610ee2565b916080939160018060a01b03168352602083015260606040830152806060830152806000848401376000828201840152601f01601f1916010190565b906020612048928181520190610f05565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8190556001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2565b1561237257565b60405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606490fd5b6000805160206158e0833981519152805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b634e487b7160e01b600052603260045260246000fd5b9082101561240c5761028d9160051b810190612207565b6123df565b908092918237016000815290565b6040519061242c8261114d565b60008252565b3d1561245d573d9061244382612251565b91612451604051938461119f565b82523d6000602084013e565b606090565b94939291906001600160581b03198616156121a8576001600160f81b03198616600160f81b811415908161251e575b5061250c5761249f8661356a565b6001600160a01b036124b3611f2588611e7a565b16156124c2575b505050505050565b61250195610aff6124e96000805160206158e08339815191525463ffffffff9060a81c1690565b92610ac76124f56111c0565b63ffffffff9095168552565b3880808080806124ba565b6040516361c4e91b60e11b8152600490fd5b600160f91b1415905038612491565b9060405161253a81611132565b82546001600160a01b039081168252600190930154928316602082015260589290921b6001600160f81b0319166040830152565b959294919390946125916106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f000000000000000000000000000000000000000000000000000000000000000083161415806126de575b156126ce5760405163ecd0596160e01b8152600480820152911695906020816024818a5afa9081156107c5576000916126af575b50156107f35760405163d68f602560e01b81529660008880612621363433600485016122ca565b0381838b5af19788156107c55760009861268e575b506126429697986139be565b803b1561021357604051630b9dfbed60e11b815291600091839182908490829061266f9060048301612306565b03925af180156107c557612681575b50565b806107bf6102239261111a565b6126429798506126a8903d806000833e6107e4818361119f565b9796612636565b6126c8915060203d60201161082d5761081f818361119f565b386125fa565b50509193909294610223966139be565b50303314156125c6565b91602061204893818152019161204b565b6bffffffffffffffffffffffff19903581811693926014811061271b57505050565b60140360031b82901b16169150565b60018103612863575060581b600160581b600160f81b0316600160f81b17906127ee6127c7611f6f6127c16127bb6127b461277161276789611e7a565b5463ffffffff1690565b6000805160206158e083398151915290612793825463ffffffff9060a81c1690565b9063ffffffff9081168183161461284f575b50505460a81c63ffffffff1690565b9786611d57565b906126f9565b60601c90565b6127de6127d26111c0565b63ffffffff9096168652565b6001600160a01b03166020850152565b61282860148201358201916034810135810190605481013501946014860135936034601484013593019160346014830135920190876135c5565b60048114612836575b505050565b6104fe6128499160346102239501611d1b565b90613d9c565b600161285c9201166123ad565b38806127a5565b600281036128bf5750916128b061022393612895611f6f6127c16127bb60148801358801966034890135890198611d57565b928391601482013591603401906001600160a01b0316613d53565b60346014830135920190613ba0565b9091906003810361293f575061293a611f6f61292a610223958461292560186127c197013582016127c160388401358401996128fe6104fe8787611d1b565b9061291f611f6f61290f8989611d46565b60188801359760380196916126f9565b91613a2c565b611d46565b60188601359560380194916126f9565b613ba0565b90600482036129d4576001600160a01b03831693843b156102135761297e94600092836040518098819582946306d61fe760e41b8452600484016126e8565b03925af19283156107c5576000805160206158a0833981519152936129c1575b50604080519182526001600160a01b03909216602082015290819081015b0390a1565b806107bf6129ce9261111a565b3861299e565b60058203612a12576001600160a01b03831693843b156102135761297e94600092836040518098819582946306d61fe760e41b8452600484016126e8565b60068203612a50576001600160a01b03831693843b156102135761297e94600092836040518098819582946306d61fe760e41b8452600484016126e8565b604051631092ef5760e11b8152600490fd5b359060208110612a70575090565b6000199060200360031b1b1690565b919060405190612a8e8261114d565b819360008352116102135760206000910152565b929192612aae82612251565b91612abc604051938461119f565b829481845281830111610213578281602093846000960137010152565b60018103612b02575061267e92919060581b600160581b600160f81b0316600160f81b17613fef565b60028103612b1f575061267e9291906001600160a01b0316613f6a565b60038103612b4a575050612b448280612b3e6104fe61267e9686611d1b565b93611d29565b91613eb0565b909160048203612bde57612bab61299e916000805160206158c083398151915295612b846000805160206158e08339815191525460581b90565b612b90611f2582611e7a565b6001600160a01b03888116911614612bb1575b503691612aa2565b83613e01565b612bbd612bd891611e7a565b8054640100000000600160c01b031916640100000000179055565b38612ba3565b60058203612c6f576000805160206158e08339815191525460581b5b612c0d612c078684611d65565b90612a62565b906001600160f81b03198116600160f91b14612c44575b5050612bab61299e916000805160206158c0833981519152953691612aa2565b60081b6001600160e01b03191614612c5d573880612c24565b6040516313002bdd60e31b8152600490fd5b60068203612a50576000805160206158e08339815191525460581b612bfa565b60405190612c9c82611168565b60006020838281520152565b612cbc818060081b918160301b9160501b90565b929091600160f81b916001600160f81b031991908216838114159081612d60575b81612d55575b81612d46575b50612d3c5716908114159081612d32575b50612d2b576001600160e01b031916612d25576001600160501b031916612d2057600190565b600090565b50600090565b5050600090565b9050151538612cfa565b5050505050600090565b607f60f91b1415905038612ce9565b838114159150612ce3565b8015159150612cdd565b91612d7a91610223959493613fef565b614347565b9061267e9291614147565b60071115612d2057600190565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460408051338152346020820152a1565b612de5612de06000356001600160e01b031916611fc3565b61252d565b80516001600160a01b03908190612dfd908216611f6f565b1615612f4f57815160609082908190612e1e906001600160a01b0316611f6f565b16600181141580612f45575b15612f055750508251612e4a91506001600160a01b031636903490613818565b60408301516001600160f81b031990811680612ece5750506020830151612e79906001600160a01b03166143da565b93905b15612ec657516001600160a01b0316918083169060018214159182612ebb575b5050612eab575b825160208401f35b612eb491613945565b3880612ea3565b141590503880612e9c565b835160208501fd5b03612ef3576020830151612eec906001600160a01b031636906138f7565b9390612e7c565b604051632d6a6bb760e01b8152600490fd5b03612e4a57337f0000000000000000000000000000000000000000000000000000000000000000831614612e4a576040516348f5c3ed60e01b8152600490fd5b5081811415612e2a565b604051631cd4b64760e21b8152600490fd5b6001600160a01b031660009081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b9182358060f81c80600014612fe05780600114612fd357600214612fbd57600080fd5b6001600160d81b03191692600501916004190190565b5092601501916014190190565b5050600160009301916000190190565b90926080926120489694835260018060a01b031660208301526040820152816060820152019161204b565b90919261303a9461302e9185858561441a565b9492939196909661450e565b509065ffffffffffff80911642109182156130c0575b50506130ad5761308e6130646020966130cc565b60405163392dffaf60e01b8152978896879586959193916001600160e01b03191660048701612ff0565b03916001600160a01b03165afa9081156107c55760009161212f575090565b506001600160e01b031995945050505050565b16421190503880613050565b6120489060405160208101917f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83835260408201526040815261310d81611132565b519020614537565b90818060081b9160ff839260f01c1660021461312d57565b6001600160d81b031983169150565b9080601f830112156102135781602061204893359101612aa2565b9190610120838203126102135761316c6111cd565b9261317681610218565b8452602081013560208501526040810135916001600160401b039283811161021357816131a491840161313c565b6040860152606082013583811161021357816131c191840161313c565b60608601526080820135608086015260a082013560a086015260c082013560c086015260e082013583811161021357816131fc91840161313c565b60e086015261010092838301359081116102135761321a920161313c565b90830152565b90816020910312610213575190565b80516001600160a01b0316825261204891906132ad61327d61326b61012060208501516020870152604085015190806040880152860190610f05565b60608401518582036060870152610f05565b6080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152610f05565b916101008092015191818403910152610f05565b9392916132de90604092865260606020870152606086019061322f565b930152565b9291906132de60209160408652604086019061322f565b92909260009261330a3682613157565b91610100918281019161331d8383612207565b90949093600160f81b936001600160f81b03199384168514613466575b5050508716036133c7575050604051639700320360e01b81529360209285928391600091839161336d91600484016132e3565b039260581c6001600160a01b03165af19081156107c55761204892600092613396575b50614a46565b6133b991925060203d6020116133c0575b6133b1818361119f565b810190613220565b9038613390565b503d6133a7565b909460081b93909291600160f01b6133e461217961217288611ffb565b166134545760006134056133ff60209661342f99858a61484d565b94614a46565b604051630ccab7a160e01b8152979096889586948593926001600160e01b031916600485016132c1565b03926001600160a01b03165af19081156107c557612048926000926133965750614a46565b6040516314b9743f60e01b8152600490fd5b9091955061348293985061347b929450612207565b908861464b565b9691929093613495858995993691612aa2565b9086015238808061333a565b6000805160206158e083398151915280549163ffffffff92600a848260a81c1601908482116135545782851691851682116135425760c81c84161015613530576000805160206158e0833981519152805463ffffffff60c81b191660c89290921b63ffffffff60c81b1691909117905554818160c81c1691829160a81c16106135275750565b610223906123ad565b604051633ab3447f60e11b8152600490fd5b60405163e60fd64760e01b8152600490fd5b634e487b7160e01b600052601160045260246000fd5b60207f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae88916000805160206158e08339815191528160581c6001600160581b0360a81b825416179055604051906001600160581b0319168152a1565b91939092946135d661276784611e7a565b936000805160206158e0833981519152946135f9865463ffffffff9060a81c1690565b63ffffffff8092818084169116146137c3575b50506020820180516001600160a01b0397919291613639918916156137ba575b5460a81c63ffffffff1690565b8161364b610621865163ffffffff1690565b91161490811591613790575b50613530576136a66136b39261366c87611e7a565b815181546020938401516001600160c01b031990911663ffffffff9290921691909117921b640100000000600160c01b0316919091179055565b516001600160a01b031690565b9160018584160361377f575b5050506001600160f81b03198116600160f81b8103613763575060581c1690813b15610213576040516306d61fe760e41b815292600091849182916137089190600484016126e8565b038183855af19081156107c5576000805160206158a0833981519152926129bc92613750575b5060408051600181526001600160a01b03909216602083015290918291820190565b806107bf61375d9261111a565b3861372e565b909350600160f91b1415905061250c576102239160081b614bc8565b61378892613ba0565b3880806136bf565b905061379e61276787611e7a565b906137b0610621855163ffffffff1690565b9116101538613657565b6001845261362c565b60016137d09201166123ad565b388161360c565b6040516137e381611168565b600681526512d95c9b995b60d21b60208201529060405161380381611168565b6005815264302e332e3160d81b602082015290565b60405163d68f602560e01b815233600482015260248101929092526060604483015260648201839052600092839183918290849060849083908084838501378181018301849052601f01601f191681010301926001600160a01b03165af19182156107c557809261388857505090565b61204892503d8091833e6107e4818361119f565b600092836138c395936040519687958694859363d68f602560e01b8552336004860161206c565b03926001600160a01b03165af19081156107c5576000916138e2575090565b61204891503d806000833e6107e4818361119f565b60009060405192808385378338925af4913d82523d6000602084013e60203d830101604052565b60009192806040519485378338925af4913d82523d6000602084013e60203d830101604052565b6001600160a01b0316803b1561021357604051630b9dfbed60e11b815260206004820152916000918391829084908290613983906024830190610f05565b03925af180156107c5576139945750565b6102239061111a565b80511561240c5760200190565b805182101561240c5760209160051b010190565b96959192939694909460005b8681106139dc57505050505050509050565b80613a1d8a60019360051b8501356139f381610980565b613a0984613a01818c6139aa565b51938c6123f5565b90613a15868b8b6123f5565b9490936135c5565b016139ca565b901561240c5790565b6001600160a01b03939192919084831615613b98575b613a4b90611fc3565b94613a77613a6a613a5c8385613a23565b356001600160f81b03191690565b6001600160f81b03191690565b946001600160f81b031980871680613b795750509080613a9992861693611d73565b823b1561021357613ac492600092836040518096819582946306d61fe760e41b8452600484016126e8565b03925af19485156107c557613b29613b499360019361022398613b66575b5060408051600381526001600160a01b03881660208201526000805160206158a08339815191529190a15b82546001600160a01b0319166001600160a01b03909116178255565b0180546001600160a01b0319166001600160a01b03909316929092178255565b805460ff60a01b191660589290921c60ff60a01b16919091179055565b806107bf613b739261111a565b38613ae2565b925092505094919403612ef3576001613b4991613b2961022396613b0d565b849250613a42565b6001600160a01b0316919082158015613d49575b6128315760405163d60b347f60e01b8152306004820152602081602481875afa9081156107c557600091613d2a575b50613c7b579080613bf392611d73565b9190813b15610213576040516306d61fe760e41b81529260009184918291613c1f9190600484016126e8565b038183855af19081156107c5576000805160206158a0833981519152926129bc92613c68575b505b60408051600481526001600160a01b03909216602083015290918291820190565b806107bf613c759261111a565b38613c45565b6001600160f81b031980613c92613a5c8585613a23565b1614613cb3575b50506129bc6000805160206158a083398151915291613c47565b9080613cbe92611d73565b9190813b15610213576040516306d61fe760e41b81529260009184918291613cea9190600484016126e8565b038183855af19081156107c5576000805160206158a0833981519152926129bc92613d17575b5091613c99565b806107bf613d249261111a565b38613d10565b613d43915060203d60201161082d5761081f818361119f565b38613be3565b5060018314613bb4565b9092613d5f9082614ecc565b6001600160a01b031691823b156102135761398392600092836040518096819582946306d61fe760e41b845260206004850152602484019161204b565b7f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a91606091613dce82610e5a83611eb3565b600160ff198254161790556040519163ffffffff60e01b1682526001600160581b031916602082015260016040820152a1565b60407f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3919392935a825195613e6187613e536020820193638a91b0e360e01b8552602060248401526044830190610f05565b03601f19810189528861119f565b6000918291828587519a613e748c61114d565b828c525193f1943d9081613ea7575b6020818360009352013e81516001600160a01b0390911681528415156020820152a1565b60009150613e83565b613ebd9093929193611fc3565b80546001600160a01b031981168255600190910180546001600160a01b03928316959193909290605884901b6001600160f81b03191615613f0e575b505082546001600160a81b0319169092555050565b6000805160206158c08339815191529382613f31613f5e95613f38943691612aa2565b9116613e01565b5083546040805160038152929091166001600160a01b0316602083015290918291820190565b0390a138808080613ef9565b6001600160a01b0390811660008181527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b8660205260409081902080546001600160a01b0319811690915590921694936000805160206158c083398151915293613fdf91613fd991369190612aa2565b82613e01565b50815190600282526020820152a1565b92919061402061400e6000805160206158e08339815191525460581b90565b6001600160581b031980871691161490565b612c5d57614030611f2585611e7a565b9361405161403d82611e7a565b8054640100000000600160c01b0319169055565b6001600160f81b03198116600160f81b810361409757509161372e613fd96129bc936000805160206158c08339815191529560018060a01b039060581c16933691612aa2565b909250600160f91b0361250c576102239160081b614f56565b6040516140bc81611168565b600181528060005b6020808210156140df579060606020928285010152016140c4565b50505090565b906140ef826111da565b6140fc604051918261119f565b828152809261410d601f19916111da565b019060005b82811061411e57505050565b806060602080938501015201614112565b90604061204892600081528160208201520190610f05565b61415b818060081b918160301b9160501b90565b5090936001600160f81b031993600160f81b9390925084168381036141e657505061418d908035019060208201913590565b9290931680156000146141a55750506120489161525d565b036141b357612048916151a0565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b949594909190806142835750906141fc916150f4565b939092946142086140b0565b97168061422d57505061421a93615145565b6142238361399d565b5261267e8261399d565b036141b35761423b9361511c565b6142448461399d565b52610223577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76129bc6142768461399d565b516040519182918261412f565b9195939182036141b3576142ba906142b461429c6140b0565b97806142ae6127c16127bb8387611d57565b93611d90565b9161391e565b6142c68795929561399d565b52169081036143045750156142d757565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76129bc6142768461399d565b6141b3576102235760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b6044820152606490fd5b9091906001600160a01b0316801580156143d0575b61283157811561240c576000805160206158c0833981519152926129bc926001600160f81b031982358116146143b0575b505060408051600481526001600160a01b03909216602083015290918291820190565b6143c181613fd9926143c894611d73565b3691612aa2565b50388061438d565b506001811461435c565b600080604092835136810185523683823784516014810186523360601b90528260143601925af1918151913d83523d6000602085013e60203d8401019052565b848461449d9261448897969498956040519161443583611183565b61449760009b8c92838652836020870152604086019d8e52606086019c8d918583528560808901528560a0890152606060c089015260e088019286845261010089019687529063ffffffff60e01b169052565b6001600160a01b039091169052565b526152f6565b60ff806144b66144b0613a5c8786613a23565b60f81c90565b16036144fc576144e56144d0846144e0956144f594611d73565b9490955163ffffffff60e01b1690565b611ffb565b5460101c6001600160a01b031690565b9351929190565b60405163b32eeb6960e01b8152600490fd5b8065ffffffffffff91828160a01c1692831560011461452f575b5060d01c92565b925038614528565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f0000000000000000000000000000000000000000000000000000000000000000461416156145c4575b671901000000000000600052601a52603a526042601820906000603a52565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000006040820152466060820152306080820152206145a5565b91929092614657612c8f565b906146629085611d57565b61466b916126f9565b60601c602082018190526000805160206158e08339815191525460a81c63ffffffff1680835260349560148082013582018089019791959294919360548601358601808b019490880135939092878c01358801808a013593908d0192918a0135918891908d8436906146dc92612aa2565b8051906020012091366146f0908888612aa2565b8051906020012036614703908b8d612aa2565b8051602091820120604080517fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c5059381019384526001600160581b0319989098169088015263ffffffff9390931660608701526001600160a01b0393909316608086015260a085019390935260c084019290925260e0808401929092529082529061478f6101008261119f565b51902061479b90614537565b607489013589018d8b82013591016147b292615548565b9a6147bd94886135c5565b6147c781836156e5565b6147d091611d1b565b6147d991611e4e565b6147e291613d9c565b6094810135019293830192013590565b805482101561240c5760005260206000200190600090565b6001600160c01b0319903581811693926008811061482757505050565b60080360031b82901b16169150565b60409061204893928152816020820152019061322f565b60009493916001868161485f85611ffb565b016000835b6148a5575b5050505060ff806148806144b0613a5c8789613a23565b16036144fc5761010061489d6143c1856144e59661204898611d73565b910152611ffb565b8197969754811015614a3e576148d66148ce6148c183856147f2565b90549060031b1c60501b90565b908160501c90565b9890976148f26148ec6144b0613a5c8585613a23565b60ff1690565b808403614a0d575090818161492b61491f6149196149138461494898611dad565b9061480a565b60c01c90565b6001600160401b031690565b6009019161493d6143c1848484611dbe565b6101008b0152611e36565b989098975b600160f01b1615614962575b50830183614864565b998661499f929b60018060a01b036040918983518092633894f6e760e11b8252818b868260209c8d9760049c63ffffffff60e01b168d8401614836565b0393165af19586156107c55788966149ee575b505084166149d45750506149ca859493928592614a46565b9a91929350614959565b51631f24c1fb60e11b81529081018c815281906020010390fd5b614a05929650803d106133c0576133b1818361119f565b9338806149b2565b9099919890831115614a2b57604051630760bdcf60e11b8152600490fd5b614a3361241f565b61010088015261494d565b969596614869565b6001600160a01b03818318811615606083811b848601821b9081149186901b141717600114614a7757505050600190565b65ffffffffffff60a01b80831693906001600160d01b031984811691908316908615614ad9575b8381168015614ad2575b878110908818028088189714614aca575b508181119082180218921716171790565b955038614ab9565b5080614aa8565b955085614a9e565b8054906000906000815582614af557505050565b6000526020600020918201915b828110614b0e57505050565b818155600101614b02565b6001600160501b03199035818116939260168110614b3657505050565b60160360031b82901b16169150565b80546801000000000000000081101561112d57614b67916001820181556147f2565b819291549060031b9160501c821b9160018060b01b03901b1916179055565b9092809260209483528483013701016000815290565b6001600160f01b03199035818116939260028110614bb957505050565b60020360031b82901b16169150565b91908035016020808201913560fe81118015614ec4575b614eb257600180614bef87611ffb565b0154614e99575b60001982019260005b848110614d6c5750505093614cc0614cb98387614c59614caa614c91612179614c8b614c8587614cdc9e9f8e614c80614cea9f8f90611f6f6127c16127bb614c4b614c519489896123f5565b90611de9565b9a8b91611ffb565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b6123f5565b90611e17565b90614b9c565b614c9a88611ffb565b9060f01c61ffff19825416179055565b6001600160a01b0316966123f5565b8091611dfa565b6040519586939092906001600160e01b03191660208501614b86565b03601f19810184528361119f565b803b15610213576000614d1192604051809481926306d61fe760e41b835260048301612306565b038183855af19081156107c5576000805160206158a0833981519152926129bc92614d59575b5060408051600681526001600160a01b03909216602083015290918291820190565b806107bf614d669261111a565b38614d37565b614dad83614d798a611ffb565b01614da7614d9a614d94614d8e868a8d6123f5565b90611ddb565b90614b19565b6001600160501b03191690565b90614b45565b614dc7611f6f611f6f6127c16127bb614c4b868a8d6123f5565b90614dd6614cb982878a6123f5565b92614df78b614cdc604096875195869363ffffffff60e01b168a8501614b86565b803b156102135783516306d61fe760e41b8152916000918391829084908290614e239060048301612306565b03925af180156107c5578593614e5d6127c16127bb614c4b878c8f6000805160206158a083398151915299614e7d99614e86575b506123f5565b9051600581526001600160a01b0390911660208201529081906040820190565b0390a101614bff565b806107bf614e939261111a565b38614e57565b614ead6001614ea788611ffb565b01614ae1565b614bf6565b60405163b62d956d60e01b8152600490fd5b508015614bdf565b6000805160206158a083398151915291604091906001600160a01b0380821615614f4d575b90911660008181527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b8660205283902080546001600160a01b0319166001600160a01b0390931692909217909155815190600282526020820152a1565b60019150614ef1565b91908035019160209060208401933590614f6f81611ffb565b926001808501600181540185036150e2576000825b615036575b50505050614fd691614fd182614cc06102239798614fae6001614ea7614cdc98611ffb565b8754614fc59060101c6001600160a01b0316611f6f565b946000198101916123f5565b613e01565b5080546000805160206158c083398151915290615023906150029060101c6001600160a01b0316611f6f565b60408051600681526001600160a01b03909216602083015290918291820190565b0390a180546001600160b01b0319169055565b81548110156150dd579082826000805160206158c08339815191526150d28c6150a46150b28a612bab8d8f8961508a916150798d9f8f6148ce916148c1916147f2565b6001600160a01b03169990506123f5565b60409691875195869463ffffffff60e01b16908501614b86565b03601f19810183528261119f565b5051600581526001600160a01b0390911660208201529081906040820190565b0390a1019091614f84565b614f89565b60405163013dcc8d60e31b8152600490fd5b908060141161021357813560601c928160341161021357601483013592603401916033190190565b906000928491604051958692833738935af1913d82523d6000602084013e60203d830101604052565b9092600092819594604051968792833738935af115615174573d82523d6000602084013e60203d830101604052565b503d6000823e3d90fd5b919081101561240c5760051b81013590605e1981360301821215610213570190565b9190916151ac836140e5565b9260005b8181106151bc57505050565b806151ca600192848661517e565b80356151d581610202565b6151f6602080936040936151eb85830183612207565b93909201359061511c565b615200858b6139aa565b521561520f575b5050016151b0565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb79161525361523e858b6139aa565b51838051948594888652850152830190610f05565b0390a13880615207565b919091615269836140e5565b9260005b81811061527957505050565b806152af602061528c600194868861517e565b803561529781610202565b6152a46040830183612207565b939092013590615145565b6152b982886139aa565b526152c481876139aa565b500161526d565b90926080926120489594835260018060a01b0316602083015260408201528160608201520190610f05565b91906060830160019360016153156144e0845163ffffffff60e01b1690565b01936000936000958054965b87811061533357505050505050505050565b806153456148ce6148c18c94866147f2565b6001600160a01b031660a088019081526080880195909161536e906001600160f01b0319168752565b6153886153816144b0613a5c8a85613a23565b60ff168952565b6153966148ec895160ff1690565b80840361551057508681816153bb61491f61491961491361540f9c9d6153e298611dad565b60208c018181528c60c06153d76143c160099586018789611dbe565b910152510191611e36565b959095965b51600160f11b90615401906001600160f01b031916612179565b166001600160f01b03191690565b1561541c575b5001615321565b51909150615432906001600160a01b0316611f6f565b865161545690615449906001600160e01b03191681565b6001600160e01b03191690565b60e08701519091906001600160a01b03169161549b6101008901519360c08a01516040948551808095819463184dfdbb60e11b835260209a8b9760049a8b86016152cb565b03915afa9384156107c5578b946154f1575b50506001600160a01b0383166154d65750860180518b93926154ce91614a46565b905238615415565b9051631f24c1fb60e11b815290810183815281906020010390fd5b615508929450803d106133c0576133b1818361119f565b9138806154ad565b83919694501060001461552f57604051630760bdcf60e11b8152600490fd5b61540f8b9361553e3688612a7f565b60c08a01526153e7565b6000805160206158e08339815191525460009493929060581b916001600160f81b03198316600160f81b810361560b5750604051637aa8f17760e11b81529360209385939092849283926155a092306004860161206c565b039160581c6001600160a01b03165afa9081156107c5576000916155ec575b505b6001600160e01b0319166374eca2c160e11b016155da57565b6040516362467c7760e11b8152600490fd5b615605915060203d60201161215157612149818361119f565b386155bf565b919550929190600160f91b0361250c5760209161562e9160081b9584308861441a565b60405163392dffaf60e01b8152929792958694938593849361566193909230906001600160e01b03191660048701612ff0565b03916001600160a01b03165afa9081156107c557600091615683575b506155c1565b61569c915060203d60201161215157612149818361119f565b3861567d565b156156a957565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b6044820152606490fd5b6156f26104fe8383611d1b565b90600483101561570157505050565b602c83106158915761571c611f6f6127c16127bb8685611d46565b602c8201358201602c604c820191013591604c840135840194615756615748613a6a613a5c8787613a23565b6001600160f81b0319161590565b80615800575b9461579d61293a95611f6f956157a2956102239b956127c19a6157b2575b61578d611f6f6127c16127bb8a8a611e25565b916001600160a01b031690613a2c565b611e25565b602c86013595604c0194916126f9565b6157fb606c87013587016157f5602c604c8301920135806157dc611f6f6127c16127bb8488611d57565b936157f0856001600160a01b038a16614ecc565b611d90565b91613ba0565b61577a565b5091939092956040519163ecd0596160e01b83526020838061582a60048201906002602083019252565b03816001600160a01b0389165afa9283156107c557610223986127c19761293a97611f6f976157a29761579d95600091615872575b50959a50959b509550955095505061575c565b61588b915060203d60201161082d5761081f818361119f565b3861585f565b5050600461022391146156a256fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Deployed Bytecode
0x6080604052600436101561001d575b36612dc85761001b612d97565b005b60003560e01c8063112d3a7d146101fd578063150b7a02146101f85780631626ba7e146101f357806319822f7c146101ee5780631f1b92e3146101e95780633659cfe6146101e45780633c3b752b146101df57806352141cd9146101da57806357b3a5f4146101d55780636e6fa0c6146101d0578063721e67f4146101cb57806384b0196e146101c65780638dd7712f146101c157806390ef8862146101bc5780639198bdf5146101b75780639517e29f146101b25780639cfd7cff146101ad578063a65d69d4146101a8578063a71763a8146101a3578063adb610a31461019e578063b8afe17d14610199578063bc197c8114610194578063c3e589781461018f578063d03c79141461018a578063d691c96414610185578063e6f3d50a14610180578063e9ae5c531461017b578063f1f7f0f914610176578063f23a6e61146101715763f2dc691d0361000e57611cec565b611c92565b611c5a565b611b2e565b61199e565b6118ba565b61186d565b611791565b61168a565b611620565b6115ec565b6114c0565b61147b565b611424565b6112f8565b6111f1565b6110d0565b610fcc565b610f2a565b610e7e565b610e21565b610d73565b610b99565b6109c2565b610849565b610691565b610371565b610311565b6102b7565b610291565b6001600160a01b0381160361021357565b600080fd5b359061022382610202565b565b9181601f84011215610213578235916001600160401b038311610213576020838186019501011161021357565b6060600319820112610213576004359160243561026e81610202565b91604435906001600160401b0382116102135761028d91600401610225565b9091565b346102135760206102ad6102a436610252565b92919091611eec565b6040519015158152f35b34610213576080366003190112610213576102d3600435610202565b6102de602435610202565b6064356001600160401b038111610213576102fd903690600401610225565b5050604051630a85bd0160e11b8152602090f35b34610213576040366003190112610213576024356001600160401b0381116102135761034f6103466020923690600401610225565b9060043561209c565b6040516001600160e01b03199091168152f35b90816101209103126102135790565b606036600319011261021357600480356001600160401b0381116102135761039c9036908301610362565b60243590604435906001600160a01b03907f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328216330361065c578084926103e66020830135613115565b6001600160f81b031990911615959093909186610632575b908461040a93926132fa565b9561041c61041784611e7a565b6121db565b94159485806105f0575b6105df57602001516001600160a01b03169182169081156105ce5760019261045b61047a926000526000602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b0361052d57826104cf575b50506104be576104a89250805b6104ac575b506040519081529081906020820190565b0390f35b3490349034903490335af15038610497565b604051631a0a9b9f60e21b81528390fd5b6105269250610522916105046104fe6104f86104ed61051b95611eb3565b936060810190612207565b90611d1b565b90611e4e565b63ffffffff60e01b16600052602052604060002090565b5460ff1690565b1590565b3880610485565b8291929161059b575b5061058a576104f881606061054c930190612207565b638dd7712f60e01b916001600160e01b03199161056891611e4e565b1603610579576104a8925080610492565b60405163dbbb044b60e01b81528390fd5b604051631a0a9b9f60e21b81528490fd5b6105c8915061051b6105af61052292611eb3565b6105046104fe6105c26060880188612207565b90611d0a565b38610536565b604051631a0a9b9f60e21b81528990fd5b604051633ab3447f60e11b81528990fd5b50805163ffffffff1663ffffffff61062a6106216000805160206158e08339815191525463ffffffff9060c81c1690565b63ffffffff1690565b911610610426565b93509061040a916106526000805160206158e08339815191525460581b90565b94909192506103fe565b6040516348f5c3ed60e01b81528590fd5b6004359063ffffffff8216820361021357565b359063ffffffff8216820361021357565b6020366003190112610213576106a561066d565b6106c76106c16000805160206158e08339815191525460581b90565b60581c90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032831614158061083f575b156108345760405163ecd0596160e01b8152600480820152911690602081602481855afa9081156107c557600091610805575b50156107f35760405163d68f602560e01b81529160008380610756363433600485016122ca565b038183865af19283156107c5576000936107ca575b50610775906134a1565b803b1561021357604051630b9dfbed60e11b81529160009183918290849082906107a29060048301612306565b03925af180156107c5576107b257005b806107bf61001b9261111a565b80610ed7565b612090565b6107759193506107ec903d806000833e6107e4818361119f565b81019061226c565b929061076b565b6040516348f5c3ed60e01b8152600490fd5b610827915060203d60201161082d575b61081f818361119f565b810190612239565b3861072f565b503d610815565b505061001b906134a1565b50303314156106fc565b60203660031901126102135760043561086181610202565b61087d6106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580610976575b1561096b5760405163ecd0596160e01b8152600480820152911690602081602481855afa9081156107c55760009161094c575b50156107f35760405163d68f602560e01b8152916000838061090c363433600485016122ca565b038183865af19283156107c55760009361092b575b5061077590612317565b610775919350610945903d806000833e6107e4818361119f565b9290610921565b610965915060203d60201161082d5761081f818361119f565b386108e5565b505061001b90612317565b50303314156108b2565b6001600160581b031981160361021357565b9181601f84011215610213578235916001600160401b038311610213576020808501948460051b01011161021357565b346102135760a03660031901126102135760048035906109e182610980565b602435906109ee82610202565b6001600160401b0360443581811161021357610a0d9036908401610225565b909160643581811161021357610a269036908601610225565b92909160843590811161021357610a409036908701610992565b9490966001600160581b0319610a8081610a79610a6c6000805160206158e08339815191525460581b90565b6001600160581b03191690565b161561236b565b891615610b88576001600160f81b03198916600160f81b8114159081610b79575b50610b685788610ab6610b049798999a61356a565b610ad7610ac16111c0565b60018152925b6001600160a01b03166020840152565b6000805160206158e0833981519152805463ffffffff60a81b1916600160a81b1790556135c5565b6135c5565b60005b818110610b1057005b600080610b1e8385886123f5565b60409391610b30855180938193612411565b039082305af1610b3e612432565b5015610b4d5750600101610b07565b51636534eae560e11b81528084019182529081906020010390fd5b6040516361c4e91b60e11b81528790fd5b600160f91b1415905038610aa1565b604051631a0a9b9f60e21b81528790fd5b6080366003190112610213576004803590610bb382610980565b60243591610bc083610202565b6001600160401b039260443584811161021357610be09036908501610225565b909460643590811161021357610bf99036908601610225565b91610c166106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580610d57575b15610d4657169660405163ecd0596160e01b815260208180610c748b8201906004602083019252565b03818c5afa9081156107c557600091610d27575b5015610d165760405163d68f602560e01b81529460008680610cae3634338e85016122ca565b0381838d5af19586156107c557600096610cf7575b50610cce9596612462565b823b15610213576107a29260009283604051809681958294630b9dfbed60e11b84528301612306565b610cce9650610d10903d806000833e6107e4818361119f565b95610cc3565b6040516348f5c3ed60e01b81528790fd5b610d40915060203d60201161082d5761081f818361119f565b38610c88565b505092909361001b96929550612462565b5030331415610c4b565b6001600160e01b031981160361021357565b34610213576020366003190112610213576104a8610db5600435610d9681610d61565b600060408051610da581611132565b8281528260208201520152611fc3565b60405190610dc282611132565b80546001600160a01b0390811680845260019092015480821660208086019182526001600160f81b031960589390931b831660409687019081528651958652915190931692840192909252905116918101919091529081906060820190565b3461021357604036600319011261021357602060ff610e72600435610e4581610980565b610e5a60243591610e5583610d61565b611eb3565b9063ffffffff60e01b16600052602052604060002090565b54166040519015158152f35b34610213576020366003190112610213576020610eb4600435610ea081610202565b6000604051610eae8161114d565b52612f61565b60405190610ec18261114d565b546001600160a01b031690819052604051908152f35b600091031261021357565b60005b838110610ef55750506000910152565b8181015183820152602001610ee5565b90602091610f1e81518092818552858086019101610ee2565b601f01601f1916010190565b3461021357600036600319011261021357610f79610f466137d7565b90604051928392600f60f81b8452610f6b60209360e0602087015260e0860190610f05565b908482036040860152610f05565b90466060840152306080840152600060a084015282820360c0840152602060605192838152019160809160005b828110610fb557505050500390f35b835185528695509381019392810192600101610fa6565b6040366003190112610213576004356001600160401b03811161021357610ff7903690600401610362565b6001600160a01b03907f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032821633036107f357602435600090815260208190526040902054606091906001906001600160a01b0316938416141590816110a0575b61107261106b826060611079940190612207565b8091611d29565b903061391e565b501561108e5761108557005b61001b91613945565b60405163f21e646b60e01b8152600490fd5b915061107961107261106b6110c66110be61106b6060880188612207565b90348961389c565b9492505050611057565b3461021357600036600319011261021357602063ffffffff6000805160206158e08339815191525460c81c16604051908152f35b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161112d57604052565b611104565b606081019081106001600160401b0382111761112d57604052565b602081019081106001600160401b0382111761112d57604052565b604081019081106001600160401b0382111761112d57604052565b61012081019081106001600160401b0382111761112d57604052565b90601f801991011681019081106001600160401b0382111761112d57604052565b6040519061022382611168565b6040519061022382611183565b6001600160401b03811161112d5760051b60200190565b6080366003190112610213576001600160401b036004358181116102135761121d903690600401610992565b906024358381116102135736602382011215610213578060040135611241816111da565b91604091611252604051948561119f565b8084526020906024602086019160061b8401019236841161021357602401905b8382106112ba57505050505060443584811161021357611296903690600401610992565b91606435958611610213576112b261001b963690600401610992565b95909461256e565b84823603126102135782859182516112d181611168565b6112da85610680565b8152828501356112e981610202565b83820152815201910190611272565b61130136610252565b61131d6106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032831614158061141a575b1561140e5760405163ecd0596160e01b815260048082015291169290602081602481875afa9081156107c5576000916113ef575b50156107f35760405163d68f602560e01b815293600085806113ad363433600485016122ca565b038183885af19485156107c5576000956113ce575b5061077593949561272a565b6107759495506113e8903d806000833e6107e4818361119f565b94936113c2565b611408915060203d60201161082d5761081f818361119f565b38611386565b50509161001b9361272a565b5030331415611352565b34610213576000366003190112610213576104a860405161144481611168565b60168152756b65726e656c2e616476616e6365642e76302e332e3160501b6020820152604051918291602083526020830190610f05565b34610213576000366003190112610213576040517f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b03168152602090f35b6114c936610252565b6114e56106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03283161415806115e2575b156115d65760405163ecd0596160e01b815260048082015291169290602081602481875afa9081156107c5576000916115b7575b50156107f35760405163d68f602560e01b81529360008580611575363433600485016122ca565b038183885af19485156107c557600095611596575b50610775939495612ad9565b6107759495506115b0903d806000833e6107e4818361119f565b949361158a565b6115d0915060203d60201161082d5761081f818361119f565b3861154e565b50509161001b93612ad9565b503033141561151a565b3461021357600036600319011261021357602063ffffffff6000805160206158e08339815191525460a81c16604051908152f35b3461021357602036600319011261021357604061165060043561164281610980565b61164a612c8f565b50611e7a565b602082519161165e83611168565b5463ffffffff81169283815260018060a01b03928391019160201c168152835192835251166020820152f35b346102135760a0366003190112610213576116a6600435610202565b6116b1602435610202565b6001600160401b03604435818111610213576116d1903690600401610992565b5050606435818111610213576116eb903690600401610992565b505060843590811161021357611705903690600401610225565b505060405163bc197c8160e01b8152602090f35b602080825282516001600160f01b03191681830152808301516001600160a01b03166040808401919091529092015160608083015280516080830181905260a090920192908101919060005b828110611773575050505090565b83516001600160501b03191685529381019392810192600101611765565b3461021357602080600319360112610213576004356117af81610d61565b6117d460409160608380516117c381611132565b600081526000878201520152611ffb565b908051916117e183611132565b805460f081901b6001600160f01b031916845260101c6001600160a01b031684840152815160019182018054808352600091825286822083880197939490939092905b82821061184b576104a888888861183d818e038261119f565b818301525191829182611719565b845460501b6001600160501b0319168952978801979383019390830190611824565b346102135760203660031901126102135760206102ad600435612ca8565b9060406003198301126102135760043591602435906001600160401b0382116102135761028d91600401610225565b6118c33661188b565b916001600160a01b036118d533612f61565b541690811561198c57606060019460018414159485611975575b6118f99293614147565b92611965575b5050906040519060208083016020845284518091526040840191602060408360051b8701019601926000905b8382106119385786880387f35b90919293948380611954839a603f198b82030186528951610f05565b99970195949391909101910161192b565b61196e91613945565b38806118ff565b6118f99250611985363487613818565b92506118ef565b60405163710c949760e01b8152600490fd5b60603660031901126102135760048035906119b882610980565b6001600160401b0391602435838111610213576119d89036908401610225565b93604435908111610213576119f09036908501610225565b90611a0d6106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580611b24575b15611b1457169560405163ecd0596160e01b815260208180611a6b8a8201906004602083019252565b03818b5afa9081156107c557600091611af5575b5015611ae45760405163d68f602560e01b81529360008580611aa53634338d85016122ca565b0381838c5af19485156107c557600095611ac5575b50610cce9495612d6a565b610cce9550611ade903d806000833e6107e4818361119f565b94611aba565b6040516348f5c3ed60e01b81528690fd5b611b0e915060203d60201161082d5761081f818361119f565b38611a7f565b50509261001b9592919450612d6a565b5030331415611a42565b611b373661188b565b611b536106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580611c50575b15611c445760405163ecd0596160e01b815260048082015291169190602081602481865afa9081156107c557600091611c25575b50156107f35760405163d68f602560e01b81529260008480611be3363433600485016122ca565b038183875af19384156107c557600094611c04575b50610775929394612d7f565b610775939450611c1e903d806000833e6107e4818361119f565b9392611bf8565b611c3e915060203d60201161082d5761081f818361119f565b38611bbc565b50509061001b92612d7f565b5030331415611b88565b346102135760003660031901126102135760206000805160206158e08339815191525460581b604051906001600160581b0319168152f35b346102135760a036600319011261021357611cae600435610202565b611cb9602435610202565b6084356001600160401b03811161021357611cd8903690600401610225565b505060405163f23a6e6160e01b8152602090f35b346102135760203660031901126102135760206102ad600435612d8a565b906008116102135760040190600490565b906004116102135790600490565b909291928360041161021357831161021357600401916003190190565b906018116102135760040190601490565b906014116102135790601490565b906020116102135790602090565b909291928360011161021357831161021357600101916000190190565b909291928360141161021357831161021357601401916013190190565b906009116102135760010190600890565b909291928360091161021357831161021357600901916008190190565b906016116102135790601690565b906016116102135760020190601490565b909291928360161161021357831161021357601601916015190190565b906002116102135790600290565b90602c116102135760180190601490565b90939293848311610213578411610213578101920390565b6001600160e01b03199035818116939260048110611e6b57505050565b60040360031b82901b16169150565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f850602052604060002090565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f851602052604060002090565b90929060018103611f3b57506001600160a01b0392611f359250611f25915060581b600160581b600160f81b0316600160f81b17611e7a565b5460201c6001600160a01b031690565b16151590565b60028103611f7b57506001600160a01b0392611f359250611f6f9150611f62908416612f61565b546001600160a01b031690565b6001600160a01b031690565b600303611fbb57611f9c611f976104fe600193611faa95611d1b565b611fc3565b01546001600160a01b031690565b6001600160a01b0390811691161490565b505050600090565b63ffffffff60e01b166000527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b602052604060002090565b63ffffffff60e01b166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f852602052604060002090565b90816020910312610213575161204881610d61565b90565b908060209392818452848401376000828201840152601f01601f1916010190565b612048949260609260018060a01b031682526020820152816040820152019161204b565b6040513d6000823e3d90fd5b916120a691612f9a565b91906001600160f81b0319808316156121ba575b6001600160a01b0390816120d3611f6f611f2587611e7a565b16156121a8578316600160f81b03612158579060209392916120f7612115966130cc565b604051637aa8f17760e11b815296879586948593336004860161206c565b039260581c165afa9081156107c55760009161212f575090565b612048915060203d602011612151575b612149818361119f565b810190612033565b503d61213f565b509060081b92600160f11b61218661217961217287611ffb565b5460f01b90565b6001600160f01b03191690565b166121965761204893339061301b565b604051635b71057960e01b8152600490fd5b604051631a0a9b9f60e21b8152600490fd5b91506121d56000805160206158e08339815191525460581b90565b916120ba565b906040516121e881611168565b915463ffffffff81168352602090811c6001600160a01b031690830152565b903590601e198136030182121561021357018035906001600160401b0382116102135760200191813603831361021357565b90816020910312610213575180151581036102135790565b6001600160401b03811161112d57601f01601f191660200190565b602081830312610213578051906001600160401b038211610213570181601f8201121561021357805161229e81612251565b926122ac604051948561119f565b81845260208284010111610213576120489160208085019101610ee2565b916080939160018060a01b03168352602083015260606040830152806060830152806000848401376000828201840152601f01601f1916010190565b906020612048928181520190610f05565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8190556001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2565b1561237257565b60405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606490fd5b6000805160206158e0833981519152805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b634e487b7160e01b600052603260045260246000fd5b9082101561240c5761028d9160051b810190612207565b6123df565b908092918237016000815290565b6040519061242c8261114d565b60008252565b3d1561245d573d9061244382612251565b91612451604051938461119f565b82523d6000602084013e565b606090565b94939291906001600160581b03198616156121a8576001600160f81b03198616600160f81b811415908161251e575b5061250c5761249f8661356a565b6001600160a01b036124b3611f2588611e7a565b16156124c2575b505050505050565b61250195610aff6124e96000805160206158e08339815191525463ffffffff9060a81c1690565b92610ac76124f56111c0565b63ffffffff9095168552565b3880808080806124ba565b6040516361c4e91b60e11b8152600490fd5b600160f91b1415905038612491565b9060405161253a81611132565b82546001600160a01b039081168252600190930154928316602082015260589290921b6001600160f81b0319166040830152565b959294919390946125916106c16000805160206158e08339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03283161415806126de575b156126ce5760405163ecd0596160e01b8152600480820152911695906020816024818a5afa9081156107c5576000916126af575b50156107f35760405163d68f602560e01b81529660008880612621363433600485016122ca565b0381838b5af19788156107c55760009861268e575b506126429697986139be565b803b1561021357604051630b9dfbed60e11b815291600091839182908490829061266f9060048301612306565b03925af180156107c557612681575b50565b806107bf6102239261111a565b6126429798506126a8903d806000833e6107e4818361119f565b9796612636565b6126c8915060203d60201161082d5761081f818361119f565b386125fa565b50509193909294610223966139be565b50303314156125c6565b91602061204893818152019161204b565b6bffffffffffffffffffffffff19903581811693926014811061271b57505050565b60140360031b82901b16169150565b60018103612863575060581b600160581b600160f81b0316600160f81b17906127ee6127c7611f6f6127c16127bb6127b461277161276789611e7a565b5463ffffffff1690565b6000805160206158e083398151915290612793825463ffffffff9060a81c1690565b9063ffffffff9081168183161461284f575b50505460a81c63ffffffff1690565b9786611d57565b906126f9565b60601c90565b6127de6127d26111c0565b63ffffffff9096168652565b6001600160a01b03166020850152565b61282860148201358201916034810135810190605481013501946014860135936034601484013593019160346014830135920190876135c5565b60048114612836575b505050565b6104fe6128499160346102239501611d1b565b90613d9c565b600161285c9201166123ad565b38806127a5565b600281036128bf5750916128b061022393612895611f6f6127c16127bb60148801358801966034890135890198611d57565b928391601482013591603401906001600160a01b0316613d53565b60346014830135920190613ba0565b9091906003810361293f575061293a611f6f61292a610223958461292560186127c197013582016127c160388401358401996128fe6104fe8787611d1b565b9061291f611f6f61290f8989611d46565b60188801359760380196916126f9565b91613a2c565b611d46565b60188601359560380194916126f9565b613ba0565b90600482036129d4576001600160a01b03831693843b156102135761297e94600092836040518098819582946306d61fe760e41b8452600484016126e8565b03925af19283156107c5576000805160206158a0833981519152936129c1575b50604080519182526001600160a01b03909216602082015290819081015b0390a1565b806107bf6129ce9261111a565b3861299e565b60058203612a12576001600160a01b03831693843b156102135761297e94600092836040518098819582946306d61fe760e41b8452600484016126e8565b60068203612a50576001600160a01b03831693843b156102135761297e94600092836040518098819582946306d61fe760e41b8452600484016126e8565b604051631092ef5760e11b8152600490fd5b359060208110612a70575090565b6000199060200360031b1b1690565b919060405190612a8e8261114d565b819360008352116102135760206000910152565b929192612aae82612251565b91612abc604051938461119f565b829481845281830111610213578281602093846000960137010152565b60018103612b02575061267e92919060581b600160581b600160f81b0316600160f81b17613fef565b60028103612b1f575061267e9291906001600160a01b0316613f6a565b60038103612b4a575050612b448280612b3e6104fe61267e9686611d1b565b93611d29565b91613eb0565b909160048203612bde57612bab61299e916000805160206158c083398151915295612b846000805160206158e08339815191525460581b90565b612b90611f2582611e7a565b6001600160a01b03888116911614612bb1575b503691612aa2565b83613e01565b612bbd612bd891611e7a565b8054640100000000600160c01b031916640100000000179055565b38612ba3565b60058203612c6f576000805160206158e08339815191525460581b5b612c0d612c078684611d65565b90612a62565b906001600160f81b03198116600160f91b14612c44575b5050612bab61299e916000805160206158c0833981519152953691612aa2565b60081b6001600160e01b03191614612c5d573880612c24565b6040516313002bdd60e31b8152600490fd5b60068203612a50576000805160206158e08339815191525460581b612bfa565b60405190612c9c82611168565b60006020838281520152565b612cbc818060081b918160301b9160501b90565b929091600160f81b916001600160f81b031991908216838114159081612d60575b81612d55575b81612d46575b50612d3c5716908114159081612d32575b50612d2b576001600160e01b031916612d25576001600160501b031916612d2057600190565b600090565b50600090565b5050600090565b9050151538612cfa565b5050505050600090565b607f60f91b1415905038612ce9565b838114159150612ce3565b8015159150612cdd565b91612d7a91610223959493613fef565b614347565b9061267e9291614147565b60071115612d2057600190565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460408051338152346020820152a1565b612de5612de06000356001600160e01b031916611fc3565b61252d565b80516001600160a01b03908190612dfd908216611f6f565b1615612f4f57815160609082908190612e1e906001600160a01b0316611f6f565b16600181141580612f45575b15612f055750508251612e4a91506001600160a01b031636903490613818565b60408301516001600160f81b031990811680612ece5750506020830151612e79906001600160a01b03166143da565b93905b15612ec657516001600160a01b0316918083169060018214159182612ebb575b5050612eab575b825160208401f35b612eb491613945565b3880612ea3565b141590503880612e9c565b835160208501fd5b03612ef3576020830151612eec906001600160a01b031636906138f7565b9390612e7c565b604051632d6a6bb760e01b8152600490fd5b03612e4a57337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032831614612e4a576040516348f5c3ed60e01b8152600490fd5b5081811415612e2a565b604051631cd4b64760e21b8152600490fd5b6001600160a01b031660009081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b9182358060f81c80600014612fe05780600114612fd357600214612fbd57600080fd5b6001600160d81b03191692600501916004190190565b5092601501916014190190565b5050600160009301916000190190565b90926080926120489694835260018060a01b031660208301526040820152816060820152019161204b565b90919261303a9461302e9185858561441a565b9492939196909661450e565b509065ffffffffffff80911642109182156130c0575b50506130ad5761308e6130646020966130cc565b60405163392dffaf60e01b8152978896879586959193916001600160e01b03191660048701612ff0565b03916001600160a01b03165afa9081156107c55760009161212f575090565b506001600160e01b031995945050505050565b16421190503880613050565b6120489060405160208101917f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83835260408201526040815261310d81611132565b519020614537565b90818060081b9160ff839260f01c1660021461312d57565b6001600160d81b031983169150565b9080601f830112156102135781602061204893359101612aa2565b9190610120838203126102135761316c6111cd565b9261317681610218565b8452602081013560208501526040810135916001600160401b039283811161021357816131a491840161313c565b6040860152606082013583811161021357816131c191840161313c565b60608601526080820135608086015260a082013560a086015260c082013560c086015260e082013583811161021357816131fc91840161313c565b60e086015261010092838301359081116102135761321a920161313c565b90830152565b90816020910312610213575190565b80516001600160a01b0316825261204891906132ad61327d61326b61012060208501516020870152604085015190806040880152860190610f05565b60608401518582036060870152610f05565b6080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152610f05565b916101008092015191818403910152610f05565b9392916132de90604092865260606020870152606086019061322f565b930152565b9291906132de60209160408652604086019061322f565b92909260009261330a3682613157565b91610100918281019161331d8383612207565b90949093600160f81b936001600160f81b03199384168514613466575b5050508716036133c7575050604051639700320360e01b81529360209285928391600091839161336d91600484016132e3565b039260581c6001600160a01b03165af19081156107c55761204892600092613396575b50614a46565b6133b991925060203d6020116133c0575b6133b1818361119f565b810190613220565b9038613390565b503d6133a7565b909460081b93909291600160f01b6133e461217961217288611ffb565b166134545760006134056133ff60209661342f99858a61484d565b94614a46565b604051630ccab7a160e01b8152979096889586948593926001600160e01b031916600485016132c1565b03926001600160a01b03165af19081156107c557612048926000926133965750614a46565b6040516314b9743f60e01b8152600490fd5b9091955061348293985061347b929450612207565b908861464b565b9691929093613495858995993691612aa2565b9086015238808061333a565b6000805160206158e083398151915280549163ffffffff92600a848260a81c1601908482116135545782851691851682116135425760c81c84161015613530576000805160206158e0833981519152805463ffffffff60c81b191660c89290921b63ffffffff60c81b1691909117905554818160c81c1691829160a81c16106135275750565b610223906123ad565b604051633ab3447f60e11b8152600490fd5b60405163e60fd64760e01b8152600490fd5b634e487b7160e01b600052601160045260246000fd5b60207f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae88916000805160206158e08339815191528160581c6001600160581b0360a81b825416179055604051906001600160581b0319168152a1565b91939092946135d661276784611e7a565b936000805160206158e0833981519152946135f9865463ffffffff9060a81c1690565b63ffffffff8092818084169116146137c3575b50506020820180516001600160a01b0397919291613639918916156137ba575b5460a81c63ffffffff1690565b8161364b610621865163ffffffff1690565b91161490811591613790575b50613530576136a66136b39261366c87611e7a565b815181546020938401516001600160c01b031990911663ffffffff9290921691909117921b640100000000600160c01b0316919091179055565b516001600160a01b031690565b9160018584160361377f575b5050506001600160f81b03198116600160f81b8103613763575060581c1690813b15610213576040516306d61fe760e41b815292600091849182916137089190600484016126e8565b038183855af19081156107c5576000805160206158a0833981519152926129bc92613750575b5060408051600181526001600160a01b03909216602083015290918291820190565b806107bf61375d9261111a565b3861372e565b909350600160f91b1415905061250c576102239160081b614bc8565b61378892613ba0565b3880806136bf565b905061379e61276787611e7a565b906137b0610621855163ffffffff1690565b9116101538613657565b6001845261362c565b60016137d09201166123ad565b388161360c565b6040516137e381611168565b600681526512d95c9b995b60d21b60208201529060405161380381611168565b6005815264302e332e3160d81b602082015290565b60405163d68f602560e01b815233600482015260248101929092526060604483015260648201839052600092839183918290849060849083908084838501378181018301849052601f01601f191681010301926001600160a01b03165af19182156107c557809261388857505090565b61204892503d8091833e6107e4818361119f565b600092836138c395936040519687958694859363d68f602560e01b8552336004860161206c565b03926001600160a01b03165af19081156107c5576000916138e2575090565b61204891503d806000833e6107e4818361119f565b60009060405192808385378338925af4913d82523d6000602084013e60203d830101604052565b60009192806040519485378338925af4913d82523d6000602084013e60203d830101604052565b6001600160a01b0316803b1561021357604051630b9dfbed60e11b815260206004820152916000918391829084908290613983906024830190610f05565b03925af180156107c5576139945750565b6102239061111a565b80511561240c5760200190565b805182101561240c5760209160051b010190565b96959192939694909460005b8681106139dc57505050505050509050565b80613a1d8a60019360051b8501356139f381610980565b613a0984613a01818c6139aa565b51938c6123f5565b90613a15868b8b6123f5565b9490936135c5565b016139ca565b901561240c5790565b6001600160a01b03939192919084831615613b98575b613a4b90611fc3565b94613a77613a6a613a5c8385613a23565b356001600160f81b03191690565b6001600160f81b03191690565b946001600160f81b031980871680613b795750509080613a9992861693611d73565b823b1561021357613ac492600092836040518096819582946306d61fe760e41b8452600484016126e8565b03925af19485156107c557613b29613b499360019361022398613b66575b5060408051600381526001600160a01b03881660208201526000805160206158a08339815191529190a15b82546001600160a01b0319166001600160a01b03909116178255565b0180546001600160a01b0319166001600160a01b03909316929092178255565b805460ff60a01b191660589290921c60ff60a01b16919091179055565b806107bf613b739261111a565b38613ae2565b925092505094919403612ef3576001613b4991613b2961022396613b0d565b849250613a42565b6001600160a01b0316919082158015613d49575b6128315760405163d60b347f60e01b8152306004820152602081602481875afa9081156107c557600091613d2a575b50613c7b579080613bf392611d73565b9190813b15610213576040516306d61fe760e41b81529260009184918291613c1f9190600484016126e8565b038183855af19081156107c5576000805160206158a0833981519152926129bc92613c68575b505b60408051600481526001600160a01b03909216602083015290918291820190565b806107bf613c759261111a565b38613c45565b6001600160f81b031980613c92613a5c8585613a23565b1614613cb3575b50506129bc6000805160206158a083398151915291613c47565b9080613cbe92611d73565b9190813b15610213576040516306d61fe760e41b81529260009184918291613cea9190600484016126e8565b038183855af19081156107c5576000805160206158a0833981519152926129bc92613d17575b5091613c99565b806107bf613d249261111a565b38613d10565b613d43915060203d60201161082d5761081f818361119f565b38613be3565b5060018314613bb4565b9092613d5f9082614ecc565b6001600160a01b031691823b156102135761398392600092836040518096819582946306d61fe760e41b845260206004850152602484019161204b565b7f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a91606091613dce82610e5a83611eb3565b600160ff198254161790556040519163ffffffff60e01b1682526001600160581b031916602082015260016040820152a1565b60407f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3919392935a825195613e6187613e536020820193638a91b0e360e01b8552602060248401526044830190610f05565b03601f19810189528861119f565b6000918291828587519a613e748c61114d565b828c525193f1943d9081613ea7575b6020818360009352013e81516001600160a01b0390911681528415156020820152a1565b60009150613e83565b613ebd9093929193611fc3565b80546001600160a01b031981168255600190910180546001600160a01b03928316959193909290605884901b6001600160f81b03191615613f0e575b505082546001600160a81b0319169092555050565b6000805160206158c08339815191529382613f31613f5e95613f38943691612aa2565b9116613e01565b5083546040805160038152929091166001600160a01b0316602083015290918291820190565b0390a138808080613ef9565b6001600160a01b0390811660008181527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b8660205260409081902080546001600160a01b0319811690915590921694936000805160206158c083398151915293613fdf91613fd991369190612aa2565b82613e01565b50815190600282526020820152a1565b92919061402061400e6000805160206158e08339815191525460581b90565b6001600160581b031980871691161490565b612c5d57614030611f2585611e7a565b9361405161403d82611e7a565b8054640100000000600160c01b0319169055565b6001600160f81b03198116600160f81b810361409757509161372e613fd96129bc936000805160206158c08339815191529560018060a01b039060581c16933691612aa2565b909250600160f91b0361250c576102239160081b614f56565b6040516140bc81611168565b600181528060005b6020808210156140df579060606020928285010152016140c4565b50505090565b906140ef826111da565b6140fc604051918261119f565b828152809261410d601f19916111da565b019060005b82811061411e57505050565b806060602080938501015201614112565b90604061204892600081528160208201520190610f05565b61415b818060081b918160301b9160501b90565b5090936001600160f81b031993600160f81b9390925084168381036141e657505061418d908035019060208201913590565b9290931680156000146141a55750506120489161525d565b036141b357612048916151a0565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b949594909190806142835750906141fc916150f4565b939092946142086140b0565b97168061422d57505061421a93615145565b6142238361399d565b5261267e8261399d565b036141b35761423b9361511c565b6142448461399d565b52610223577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76129bc6142768461399d565b516040519182918261412f565b9195939182036141b3576142ba906142b461429c6140b0565b97806142ae6127c16127bb8387611d57565b93611d90565b9161391e565b6142c68795929561399d565b52169081036143045750156142d757565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76129bc6142768461399d565b6141b3576102235760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b6044820152606490fd5b9091906001600160a01b0316801580156143d0575b61283157811561240c576000805160206158c0833981519152926129bc926001600160f81b031982358116146143b0575b505060408051600481526001600160a01b03909216602083015290918291820190565b6143c181613fd9926143c894611d73565b3691612aa2565b50388061438d565b506001811461435c565b600080604092835136810185523683823784516014810186523360601b90528260143601925af1918151913d83523d6000602085013e60203d8401019052565b848461449d9261448897969498956040519161443583611183565b61449760009b8c92838652836020870152604086019d8e52606086019c8d918583528560808901528560a0890152606060c089015260e088019286845261010089019687529063ffffffff60e01b169052565b6001600160a01b039091169052565b526152f6565b60ff806144b66144b0613a5c8786613a23565b60f81c90565b16036144fc576144e56144d0846144e0956144f594611d73565b9490955163ffffffff60e01b1690565b611ffb565b5460101c6001600160a01b031690565b9351929190565b60405163b32eeb6960e01b8152600490fd5b8065ffffffffffff91828160a01c1692831560011461452f575b5060d01c92565b925038614528565b7fffcf20c4e2c8f8fbd611039c63fc01b52f5a4e8c94c4a00b5e680cfae24aa7dd7f000000000000000000000000bac849bb641841b44e965fb01a4bf5f074f84b4d30147f0000000000000000000000000000000000000000000000000000000000aa36a7461416156145c4575b671901000000000000600052601a52603a526042601820906000603a52565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f32ba20807d2fff2dbb34e0bcfa82982565bef566d4c0c633dc57b700b81c342760208201527fa54d0256a5ef7b691e1e01baacb06baa29013253f551f7dad7708516cb21264d6040820152466060820152306080820152206145a5565b91929092614657612c8f565b906146629085611d57565b61466b916126f9565b60601c602082018190526000805160206158e08339815191525460a81c63ffffffff1680835260349560148082013582018089019791959294919360548601358601808b019490880135939092878c01358801808a013593908d0192918a0135918891908d8436906146dc92612aa2565b8051906020012091366146f0908888612aa2565b8051906020012036614703908b8d612aa2565b8051602091820120604080517fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c5059381019384526001600160581b0319989098169088015263ffffffff9390931660608701526001600160a01b0393909316608086015260a085019390935260c084019290925260e0808401929092529082529061478f6101008261119f565b51902061479b90614537565b607489013589018d8b82013591016147b292615548565b9a6147bd94886135c5565b6147c781836156e5565b6147d091611d1b565b6147d991611e4e565b6147e291613d9c565b6094810135019293830192013590565b805482101561240c5760005260206000200190600090565b6001600160c01b0319903581811693926008811061482757505050565b60080360031b82901b16169150565b60409061204893928152816020820152019061322f565b60009493916001868161485f85611ffb565b016000835b6148a5575b5050505060ff806148806144b0613a5c8789613a23565b16036144fc5761010061489d6143c1856144e59661204898611d73565b910152611ffb565b8197969754811015614a3e576148d66148ce6148c183856147f2565b90549060031b1c60501b90565b908160501c90565b9890976148f26148ec6144b0613a5c8585613a23565b60ff1690565b808403614a0d575090818161492b61491f6149196149138461494898611dad565b9061480a565b60c01c90565b6001600160401b031690565b6009019161493d6143c1848484611dbe565b6101008b0152611e36565b989098975b600160f01b1615614962575b50830183614864565b998661499f929b60018060a01b036040918983518092633894f6e760e11b8252818b868260209c8d9760049c63ffffffff60e01b168d8401614836565b0393165af19586156107c55788966149ee575b505084166149d45750506149ca859493928592614a46565b9a91929350614959565b51631f24c1fb60e11b81529081018c815281906020010390fd5b614a05929650803d106133c0576133b1818361119f565b9338806149b2565b9099919890831115614a2b57604051630760bdcf60e11b8152600490fd5b614a3361241f565b61010088015261494d565b969596614869565b6001600160a01b03818318811615606083811b848601821b9081149186901b141717600114614a7757505050600190565b65ffffffffffff60a01b80831693906001600160d01b031984811691908316908615614ad9575b8381168015614ad2575b878110908818028088189714614aca575b508181119082180218921716171790565b955038614ab9565b5080614aa8565b955085614a9e565b8054906000906000815582614af557505050565b6000526020600020918201915b828110614b0e57505050565b818155600101614b02565b6001600160501b03199035818116939260168110614b3657505050565b60160360031b82901b16169150565b80546801000000000000000081101561112d57614b67916001820181556147f2565b819291549060031b9160501c821b9160018060b01b03901b1916179055565b9092809260209483528483013701016000815290565b6001600160f01b03199035818116939260028110614bb957505050565b60020360031b82901b16169150565b91908035016020808201913560fe81118015614ec4575b614eb257600180614bef87611ffb565b0154614e99575b60001982019260005b848110614d6c5750505093614cc0614cb98387614c59614caa614c91612179614c8b614c8587614cdc9e9f8e614c80614cea9f8f90611f6f6127c16127bb614c4b614c519489896123f5565b90611de9565b9a8b91611ffb565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b6123f5565b90611e17565b90614b9c565b614c9a88611ffb565b9060f01c61ffff19825416179055565b6001600160a01b0316966123f5565b8091611dfa565b6040519586939092906001600160e01b03191660208501614b86565b03601f19810184528361119f565b803b15610213576000614d1192604051809481926306d61fe760e41b835260048301612306565b038183855af19081156107c5576000805160206158a0833981519152926129bc92614d59575b5060408051600681526001600160a01b03909216602083015290918291820190565b806107bf614d669261111a565b38614d37565b614dad83614d798a611ffb565b01614da7614d9a614d94614d8e868a8d6123f5565b90611ddb565b90614b19565b6001600160501b03191690565b90614b45565b614dc7611f6f611f6f6127c16127bb614c4b868a8d6123f5565b90614dd6614cb982878a6123f5565b92614df78b614cdc604096875195869363ffffffff60e01b168a8501614b86565b803b156102135783516306d61fe760e41b8152916000918391829084908290614e239060048301612306565b03925af180156107c5578593614e5d6127c16127bb614c4b878c8f6000805160206158a083398151915299614e7d99614e86575b506123f5565b9051600581526001600160a01b0390911660208201529081906040820190565b0390a101614bff565b806107bf614e939261111a565b38614e57565b614ead6001614ea788611ffb565b01614ae1565b614bf6565b60405163b62d956d60e01b8152600490fd5b508015614bdf565b6000805160206158a083398151915291604091906001600160a01b0380821615614f4d575b90911660008181527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b8660205283902080546001600160a01b0319166001600160a01b0390931692909217909155815190600282526020820152a1565b60019150614ef1565b91908035019160209060208401933590614f6f81611ffb565b926001808501600181540185036150e2576000825b615036575b50505050614fd691614fd182614cc06102239798614fae6001614ea7614cdc98611ffb565b8754614fc59060101c6001600160a01b0316611f6f565b946000198101916123f5565b613e01565b5080546000805160206158c083398151915290615023906150029060101c6001600160a01b0316611f6f565b60408051600681526001600160a01b03909216602083015290918291820190565b0390a180546001600160b01b0319169055565b81548110156150dd579082826000805160206158c08339815191526150d28c6150a46150b28a612bab8d8f8961508a916150798d9f8f6148ce916148c1916147f2565b6001600160a01b03169990506123f5565b60409691875195869463ffffffff60e01b16908501614b86565b03601f19810183528261119f565b5051600581526001600160a01b0390911660208201529081906040820190565b0390a1019091614f84565b614f89565b60405163013dcc8d60e31b8152600490fd5b908060141161021357813560601c928160341161021357601483013592603401916033190190565b906000928491604051958692833738935af1913d82523d6000602084013e60203d830101604052565b9092600092819594604051968792833738935af115615174573d82523d6000602084013e60203d830101604052565b503d6000823e3d90fd5b919081101561240c5760051b81013590605e1981360301821215610213570190565b9190916151ac836140e5565b9260005b8181106151bc57505050565b806151ca600192848661517e565b80356151d581610202565b6151f6602080936040936151eb85830183612207565b93909201359061511c565b615200858b6139aa565b521561520f575b5050016151b0565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb79161525361523e858b6139aa565b51838051948594888652850152830190610f05565b0390a13880615207565b919091615269836140e5565b9260005b81811061527957505050565b806152af602061528c600194868861517e565b803561529781610202565b6152a46040830183612207565b939092013590615145565b6152b982886139aa565b526152c481876139aa565b500161526d565b90926080926120489594835260018060a01b0316602083015260408201528160608201520190610f05565b91906060830160019360016153156144e0845163ffffffff60e01b1690565b01936000936000958054965b87811061533357505050505050505050565b806153456148ce6148c18c94866147f2565b6001600160a01b031660a088019081526080880195909161536e906001600160f01b0319168752565b6153886153816144b0613a5c8a85613a23565b60ff168952565b6153966148ec895160ff1690565b80840361551057508681816153bb61491f61491961491361540f9c9d6153e298611dad565b60208c018181528c60c06153d76143c160099586018789611dbe565b910152510191611e36565b959095965b51600160f11b90615401906001600160f01b031916612179565b166001600160f01b03191690565b1561541c575b5001615321565b51909150615432906001600160a01b0316611f6f565b865161545690615449906001600160e01b03191681565b6001600160e01b03191690565b60e08701519091906001600160a01b03169161549b6101008901519360c08a01516040948551808095819463184dfdbb60e11b835260209a8b9760049a8b86016152cb565b03915afa9384156107c5578b946154f1575b50506001600160a01b0383166154d65750860180518b93926154ce91614a46565b905238615415565b9051631f24c1fb60e11b815290810183815281906020010390fd5b615508929450803d106133c0576133b1818361119f565b9138806154ad565b83919694501060001461552f57604051630760bdcf60e11b8152600490fd5b61540f8b9361553e3688612a7f565b60c08a01526153e7565b6000805160206158e08339815191525460009493929060581b916001600160f81b03198316600160f81b810361560b5750604051637aa8f17760e11b81529360209385939092849283926155a092306004860161206c565b039160581c6001600160a01b03165afa9081156107c5576000916155ec575b505b6001600160e01b0319166374eca2c160e11b016155da57565b6040516362467c7760e11b8152600490fd5b615605915060203d60201161215157612149818361119f565b386155bf565b919550929190600160f91b0361250c5760209161562e9160081b9584308861441a565b60405163392dffaf60e01b8152929792958694938593849361566193909230906001600160e01b03191660048701612ff0565b03916001600160a01b03165afa9081156107c557600091615683575b506155c1565b61569c915060203d60201161215157612149818361119f565b3861567d565b156156a957565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b6044820152606490fd5b6156f26104fe8383611d1b565b90600483101561570157505050565b602c83106158915761571c611f6f6127c16127bb8685611d46565b602c8201358201602c604c820191013591604c840135840194615756615748613a6a613a5c8787613a23565b6001600160f81b0319161590565b80615800575b9461579d61293a95611f6f956157a2956102239b956127c19a6157b2575b61578d611f6f6127c16127bb8a8a611e25565b916001600160a01b031690613a2c565b611e25565b602c86013595604c0194916126f9565b6157fb606c87013587016157f5602c604c8301920135806157dc611f6f6127c16127bb8488611d57565b936157f0856001600160a01b038a16614ecc565b611d90565b91613ba0565b61577a565b5091939092956040519163ecd0596160e01b83526020838061582a60048201906002602083019252565b03816001600160a01b0389165afa9283156107c557610223986127c19761293a97611f6f976157a29761579d95600091615872575b50959a50959b509550955095505061575c565b61588b915060203d60201161082d5761081f818361119f565b3861585f565b5050600461022391146156a256fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
-----Decoded View---------------
Arg [0] : _entrypoint (address): 0x0000000071727De22E5E9d8BAf0edAc6f37da032
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Loading...
Loading
[ Download: CSV Export ]
[ 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.