Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 135561249 | 283 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
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 Name:
Kernel
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague 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 {IModule, IValidator, IHook, IExecutor, IFallback, IPolicy, ISigner} from "./interfaces/IERC7579Modules.sol";
import {EIP712} from "solady/utils/EIP712.sol";
import {ExecLib} from "./utils/ExecLib.sol";
import {ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload} from "./types/Types.sol";
import {
CALLTYPE_SINGLE,
CALLTYPE_DELEGATECALL,
ERC1967_IMPLEMENTATION_SLOT,
VALIDATION_TYPE_ROOT,
VALIDATION_TYPE_VALIDATOR,
VALIDATION_TYPE_PERMISSION,
VALIDATION_TYPE_7702,
MODULE_TYPE_VALIDATOR,
MODULE_TYPE_EXECUTOR,
MODULE_TYPE_FALLBACK,
MODULE_TYPE_HOOK,
MODULE_TYPE_POLICY,
MODULE_TYPE_SIGNER,
HOOK_MODULE_NOT_INSTALLED,
HOOK_MODULE_INSTALLED,
HOOK_ONLY_ENTRYPOINT,
EXECTYPE_TRY,
EXECTYPE_DEFAULT,
EXEC_MODE_DEFAULT,
CALLTYPE_DELEGATECALL,
CALLTYPE_SINGLE,
CALLTYPE_BATCH,
CALLTYPE_STATIC,
MAGIC_VALUE_SIG_REPLAYABLE,
ERC1271_INVALID,
ERC1271_MAGICVALUE,
EIP7702_PREFIX
} from "./types/Constants.sol";
import {InstallExecutorDataFormat, InstallFallbackDataFormat, InstallValidatorDataFormat} from "./types/Structs.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);
error AlreadyInitialized();
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() {
if (
msg.sender != address(entrypoint) && msg.sender != address(this) // do rootValidator hook
) {
IValidator validator = ValidatorLib.getValidator(_validationStorage().rootValidator);
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();
if (ValidationId.unwrap(vs.rootValidator) != bytes21(0) || bytes3(address(this).code) == EIP7702_PREFIX) {
revert AlreadyInitialized();
}
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(HOOK_MODULE_NOT_INSTALLED)) {
// 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.3";
}
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) == HOOK_MODULE_NOT_INSTALLED) {
revert InvalidSelector();
}
// action installed
bytes memory context;
if (address(config.hook) == HOOK_ONLY_ENTRYPOINT) {
// 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();
}
} else if (address(config.hook) != HOOK_MODULE_INSTALLED) {
context = _doPreHook(config.hook, msg.value, msg.data);
}
// 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) != HOOK_MODULE_INSTALLED && address(config.hook) != HOOK_ONLY_ENTRYPOINT) {
_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 = _validateUserOp(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) == HOOK_MODULE_NOT_INSTALLED && vType != VALIDATION_TYPE_ROOT) {
revert InvalidValidator();
}
executionHook[userOpHash] = execHook;
if (address(execHook) == HOOK_MODULE_INSTALLED || address(execHook) == HOOK_MODULE_NOT_INSTALLED) {
// 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.)
}
}
}
function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4) {
return _verifySignature(hash, data);
}
// --- Execution ---
function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
external
payable
override
onlyEntryPoint
{
bytes memory context;
IHook hook = executionHook[userOpHash];
bool callHook = address(hook) != HOOK_MODULE_INSTALLED;
if (callHook) {
// 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 (callHook) {
_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) == HOOK_MODULE_NOT_INSTALLED) {
revert InvalidExecutor();
}
bytes memory context;
bool callHook = address(hook) != HOOK_MODULE_INSTALLED;
if (callHook) {
context = _doPreHook(hook, msg.value, msg.data);
}
returnData = ExecLib.execute(execMode, executionCalldata);
if (callHook) {
_doPostHook(hook, context);
}
}
function execute(ExecMode execMode, bytes calldata executionCalldata) external payable onlyEntryPointOrSelfOrRoot {
ExecLib.execute(execMode, executionCalldata);
}
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])))});
InstallValidatorDataFormat calldata data;
assembly {
data := add(initData.offset, 20)
}
_installValidation(vId, config, data.validatorData, data.hookData);
if (data.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
_grantAccess(vId, bytes4(data.selectorData[0:4]), true);
}
} else if (moduleType == MODULE_TYPE_EXECUTOR) {
InstallExecutorDataFormat calldata data;
assembly {
data := add(initData.offset, 20)
}
IHook hook = IHook(address(bytes20(initData[0:20])));
_installExecutor(IExecutor(module), data.executorData, hook);
_installHook(hook, data.hookData);
} else if (moduleType == MODULE_TYPE_FALLBACK) {
InstallFallbackDataFormat calldata data;
assembly {
data := add(initData.offset, 24)
}
_installSelector(bytes4(initData[0:4]), module, IHook(address(bytes20(initData[4:24]))), data.selectorData);
_installHook(IHook(address(bytes20(initData[4:24]))), data.hookData);
} else if (
moduleType == MODULE_TYPE_HOOK || moduleType == MODULE_TYPE_POLICY || moduleType == MODULE_TYPE_SIGNER
) {
// force call onInstall for hook, policy, signer
// NOTE: for hook, kernel does not support independent hook install,
// NOTE: for policy, kernel does not support independent policy install,
// NOTE: for signer, kernel does not support independent signer install,
// hook is expected to be paired with proper validator/executor/selector
// policy is expected to be paired with proper permissionId
// to "ADD" permission, use "installValidations()" function
IHook(module).onInstall(initData);
} else {
revert InvalidModuleType();
}
emit ModuleInstalled(moduleType, module);
}
function grantAccess(ValidationId vId, bytes4 selector, bool allow) external payable onlyEntryPointOrSelfOrRoot {
_grantAccess(vId, selector, allow);
}
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 = _clearValidationData(vId);
ValidationType vType = ValidatorLib.getType(vId);
if (vType == VALIDATION_TYPE_VALIDATOR) {
IValidator validator = ValidatorLib.getValidator(vId);
ModuleLib.uninstallModule(address(validator), deinitData);
emit IERC7579Account.ModuleUninstalled(MODULE_TYPE_VALIDATOR, address(validator));
} else if (vType == VALIDATION_TYPE_PERMISSION) {
PermissionId permission = ValidatorLib.getPermissionId(vId);
_uninstallPermission(permission, deinitData);
} else {
revert InvalidValidationType();
}
_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 == MODULE_TYPE_VALIDATOR) {
ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(module));
_clearValidationData(vId);
} else if (moduleType == MODULE_TYPE_EXECUTOR) {
_clearExecutorData(IExecutor(module));
} else if (moduleType == MODULE_TYPE_FALLBACK) {
bytes4 selector = bytes4(deInitData[0:4]);
address target;
_clearSelectorData(selector);
if (target == address(0)) {
return;
}
if (target != module) {
revert InvalidSelector();
}
deInitData = deInitData[4:];
} else if (moduleType == MODULE_TYPE_HOOK) {
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(HOOK_MODULE_INSTALLED);
}
// 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
} else if (moduleType == MODULE_TYPE_POLICY || moduleType == MODULE_TYPE_SIGNER) {
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
// 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
} else {
revert InvalidModuleType();
}
ModuleLib.uninstallModule(module, deInitData);
emit ModuleUninstalled(moduleType, module);
}
function supportsModule(uint256 moduleTypeId) external pure override returns (bool) {
return moduleTypeId < 7;
}
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(HOOK_MODULE_NOT_INSTALLED);
} else if (moduleType == MODULE_TYPE_EXECUTOR) {
return address(_executorConfig(IExecutor(module)).hook) != HOOK_MODULE_NOT_INSTALLED;
} 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.3";
}
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_SINGLE, MODULE_TYPE_POLICY, MODULE_TYPE_SIGNER, MODULE_TYPE_VALIDATOR} from "../types/Constants.sol";
import {calldataKeccak, getSender} from "../utils/Utils.sol";
import {PermissionId, getValidationResult, CallType} from "../types/Types.sol";
import {_intersectValidationData} from "../utils/KernelValidationResult.sol";
import {
PermissionSigMemory,
PermissionDisableDataFormat,
PermissionEnableDataFormat,
UserOpSigEnableDataFormat,
SelectorDataFormat,
SelectorDataFormatWithExecutorData
} from "../types/Structs.sol";
import {
VALIDATION_MODE_DEFAULT,
VALIDATION_MODE_ENABLE,
VALIDATION_TYPE_ROOT,
VALIDATION_TYPE_VALIDATOR,
VALIDATION_TYPE_PERMISSION,
VALIDATION_TYPE_7702,
SKIP_USEROP,
SKIP_SIGNATURE,
HOOK_MODULE_NOT_INSTALLED,
HOOK_MODULE_INSTALLED,
HOOK_ONLY_ENTRYPOINT,
VALIDATION_MANAGER_STORAGE_SLOT,
MAX_NONCE_INCREMENT_SIZE,
ENABLE_TYPE_HASH,
KERNEL_WRAPPER_TYPE_HASH,
ERC1271_INVALID,
ERC1271_MAGICVALUE,
MAGIC_VALUE_SIG_REPLAYABLE
} from "../types/Constants.sol";
import {ECDSA} from "solady/utils/ECDSA.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 InvalidSelectorData();
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 _grantAccess(ValidationId vId, bytes4 selector, bool allow) internal {
ValidationStorage storage state = _validationStorage();
state.allowedSelectors[vId][selector] = allow;
emit SelectorSet(selector, vId, allow);
}
// 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
function _clearValidationData(ValidationId vId) 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));
}
function _uninstallPermission(PermissionId pId, bytes calldata data) internal {
PermissionDisableDataFormat calldata permissionDisableData;
assembly {
permissionDisableData := data.offset
}
PermissionConfig storage config = _validationStorage().permissionConfig[pId];
unchecked {
if (permissionDisableData.data.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.data[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.data[permissionDisableData.data.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 permissionData) internal {
ValidationStorage storage state = _validationStorage();
PermissionEnableDataFormat calldata permissionEnableData;
assembly {
permissionEnableData := permissionData.offset
}
bytes[] calldata data = permissionEnableData.data;
// allow up to 0xfe, 0xff is dedicated for signer
if (data.length > 254 || data.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 < data.length - 1; i++) {
state.permissionConfig[permission].policyData.push(PolicyData.wrap(bytes22(data[i][0:22])));
IPolicy(address(bytes20(data[i][2:22]))).onInstall(
abi.encodePacked(bytes32(PermissionId.unwrap(permission)), data[i][22:])
);
emit IERC7579Account.ModuleInstalled(MODULE_TYPE_POLICY, address(bytes20(data[i][2:22])));
}
// last permission data will be signer
ISigner signer = ISigner(address(bytes20(data[data.length - 1][2:22])));
state.permissionConfig[permission].signer = signer;
state.permissionConfig[permission].permissionFlag = PassFlag.wrap(bytes2(data[data.length - 1][0:2]));
signer.onInstall(abi.encodePacked(bytes32(PermissionId.unwrap(permission)), data[data.length - 1][22:]));
emit IERC7579Account.ModuleInstalled(MODULE_TYPE_SIGNER, address(signer));
}
}
function _validateUserOp(
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 {
{
bool isReplayable;
if (userOpSig.length >= 32 && bytes32(userOpSig[0:32]) == MAGIC_VALUE_SIG_REPLAYABLE) {
// when replayable
userOpSig = userOpSig[32:];
userOp.signature = userOpSig;
isReplayable = true;
userOpHash = replayableUserOpHash(op, msg.sender); // NOTE : msg.sender will be entrypoint
}
if (vMode == VALIDATION_MODE_ENABLE) {
(validationData, userOpSig) = _enableMode(vId, userOpSig, isReplayable);
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 if (vType == VALIDATION_TYPE_PERMISSION) {
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)
)
);
} else if (vType == VALIDATION_TYPE_7702) {
validationData = _verify7702Signature(ECDSA.toEthSignedMessageHash(userOpHash), userOpSig)
== ERC1271_MAGICVALUE ? ValidationData.wrap(0) : ValidationData.wrap(1);
} else {
revert InvalidValidationType();
}
}
}
function replayableUserOpHash(PackedUserOperation calldata userOp, address entryPoint)
public
pure
returns (bytes32)
{
return keccak256(
abi.encode(
keccak256(
abi.encode(
getSender(userOp),
userOp.nonce,
calldataKeccak(userOp.initCode),
calldataKeccak(userOp.callData),
userOp.accountGasLimits,
userOp.preVerificationGas,
userOp.gasFees,
calldataKeccak(userOp.paymasterAndData)
)
),
entryPoint,
uint256(0)
)
);
}
function _enableMode(ValidationId vId, bytes calldata packedData, bool isReplayable)
internal
returns (ValidationData validationData, bytes calldata userOpSig)
{
UserOpSigEnableDataFormat calldata enableData;
assembly {
enableData := add(packedData.offset, 20)
}
address hook = address(bytes20(packedData[0:20]));
validationData = _enableValidationWithSig(vId, hook, enableData, isReplayable);
return (validationData, enableData.userOpSig);
}
function _enableValidationWithSig(
ValidationId vId,
address hook,
UserOpSigEnableDataFormat calldata enableData,
bool isReplayable
) internal returns (ValidationData validationData) {
(ValidationConfig memory config, bytes32 digest) = _enableDigest(vId, hook, enableData, isReplayable);
validationData = _verifyEnableSig(digest, enableData.enableSig);
_installValidation(vId, config, enableData.validatorData, enableData.hookData);
_configureSelector(enableData.selectorData);
_grantAccess(vId, bytes4(enableData.selectorData[0:4]), true);
}
function _verifyEnableSig(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 if (vType == VALIDATION_TYPE_7702) {
result = _verify7702Signature(digest, enableSig);
} else {
revert InvalidValidationType();
}
if (result != ERC1271_MAGICVALUE) {
revert EnableNotApproved();
}
}
function _verifySignature(bytes32 hash, bytes calldata signature) internal view returns (bytes4) {
ValidationStorage storage vs = _validationStorage();
(ValidationId vId, bytes calldata sig) = ValidatorLib.decodeSignature(signature);
if (ValidatorLib.getType(vId) == VALIDATION_TYPE_ROOT) {
vId = vs.rootValidator;
}
bool isReplayable = sig.length >= 32 && bytes32(sig[0:32]) == MAGIC_VALUE_SIG_REPLAYABLE;
if (isReplayable) {
sig = sig[32:];
}
ValidationType vType = ValidatorLib.getType(vId);
ValidationConfig memory vc = vs.validationConfig[vId];
if (address(vc.hook) == HOOK_MODULE_NOT_INSTALLED && vType != VALIDATION_TYPE_7702) {
revert InvalidValidator();
}
if (vType != VALIDATION_TYPE_ROOT && vc.nonce < vs.validNonceFrom) {
revert InvalidNonce();
}
if (vType == VALIDATION_TYPE_VALIDATOR) {
IValidator validator = ValidatorLib.getValidator(vId);
return validator.isValidSignatureWithSender(msg.sender, _toWrappedHash(hash, isReplayable), sig);
} else if (vType == VALIDATION_TYPE_PERMISSION) {
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, isReplayable);
} else if (vType == VALIDATION_TYPE_7702) {
return _verify7702Signature(_toWrappedHash(hash, isReplayable), sig);
} else {
revert InvalidValidationType();
}
}
function _checkPermissionSignature(
PermissionId pId,
address caller,
bytes32 hash,
bytes calldata sig,
bool isReplayable
) internal view returns (bytes4) {
(ISigner signer, ValidationData valdiationData, bytes calldata validatorSig) =
_checkSignaturePolicy(pId, msg.sender, hash, sig);
(ValidAfter validAfter, ValidUntil validUntil,) = parseValidationData(ValidationData.unwrap(valdiationData));
if (block.timestamp < ValidAfter.unwrap(validAfter) || block.timestamp > ValidUntil.unwrap(validUntil)) {
return ERC1271_INVALID;
}
return signer.checkSignature(
bytes32(PermissionId.unwrap(pId)), msg.sender, _toWrappedHash(hash, isReplayable), validatorSig
);
}
function _enableDigest(
ValidationId vId,
address hook,
UserOpSigEnableDataFormat calldata enableData,
bool isReplayable
) internal view returns (ValidationConfig memory config, bytes32 digest) {
ValidationStorage storage state = _validationStorage();
config.hook = IHook(hook);
unchecked {
config.nonce =
state.validationConfig[vId].nonce == state.currentNonce ? state.currentNonce + 1 : state.currentNonce;
}
bytes32 structHash = keccak256(
abi.encode(
ENABLE_TYPE_HASH,
ValidationId.unwrap(vId),
config.nonce,
config.hook,
calldataKeccak(enableData.validatorData),
calldataKeccak(enableData.hookData),
calldataKeccak(enableData.selectorData)
)
);
digest = isReplayable ? _chainAgnosticHashTypedData(structHash) : _hashTypedData(structHash);
}
function _configureSelector(bytes calldata selectorData) internal {
bytes4 selector = bytes4(selectorData[0:4]);
if (selectorData.length >= 44) {
SelectorDataFormat calldata data;
assembly {
data := add(selectorData.offset, 44)
}
// install selector with hook and target contract
IModule selectorModule = IModule(address(bytes20(selectorData[4:24])));
if (CallType.wrap(bytes1(data.selectorInitData[0])) == CALLTYPE_SINGLE && selectorModule.isModuleType(2)) {
// also adds as executor when fallback module is also a executor
SelectorDataFormatWithExecutorData calldata dataWithExecutor;
assembly {
dataWithExecutor := data
}
IHook executorHook = IHook(address(bytes20(dataWithExecutor.executorHookData[0:20])));
// if module is also executor, install as executor
_installExecutorWithoutInit(IExecutor(address(selectorModule)), executorHook);
_installHook(executorHook, dataWithExecutor.executorHookData[20:]);
}
_installSelector(
selector, address(selectorModule), IHook(address(bytes20(selectorData[24:44]))), data.selectorInitData
);
_installHook(IHook(address(bytes20(selectorData[24:44]))), data.hookInitData);
} else {
// set without install
if (selectorData.length != 4) {
revert InvalidSelectorData();
}
}
}
function _verify7702Signature(bytes32 hash, bytes calldata sig) internal view returns (bytes4) {
return ECDSA.recover(hash, sig) == address(this) ? ERC1271_MAGICVALUE : ERC1271_INVALID;
}
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 _toWrappedHash(bytes32 hash, bool isReplayable) internal view returns (bytes32) {
bytes32 structHash = keccak256(abi.encode(KERNEL_WRAPPER_TYPE_HASH, hash));
return isReplayable ? _chainAgnosticHashTypedData(structHash) : _hashTypedData(structHash);
}
// chain agnostic internal functions
/// @dev Returns the EIP-712 domain separator.
function _buildChainAgnosticDomainSeparator() internal view returns (bytes32 separator) {
// We will use `separator` to store the name hash to save a bit of gas.
bytes32 versionHash;
(string memory name, string memory version) = _domainNameAndVersion();
separator = keccak256(bytes(name));
versionHash = keccak256(bytes(version));
/// @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), 0x00) // NOTE : user chainId == 0 as eip 7702 did
mstore(add(m, 0x80), address())
separator := keccak256(m, 0xa0)
}
}
function _chainAgnosticHashTypedData(bytes32 structHash) internal view returns (bytes32 digest) {
// we don't do cache stuff here
digest = _buildChainAgnosticDomainSeparator();
/// @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)
}
}
}// 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 {LibERC7579} from "solady/accounts/LibERC7579.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
bytes32[] calldata pointers = LibERC7579.decodeBatch(executionCalldata);
// check if execType is revert or try
if (execType == EXECTYPE_DEFAULT) returnData = execute(pointers);
else if (execType == EXECTYPE_TRY) returnData = tryExecute(pointers);
else revert("Unsupported");
} else if (callType == CALLTYPE_SINGLE) {
// destructure executionCallData according to single exec
(address target, uint256 value, bytes calldata callData) = LibERC7579.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, bytes calldata callData) = LibERC7579.decodeDelegate(executionCalldata);
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(bytes32[] calldata pointers) internal returns (bytes[] memory result) {
uint256 length = pointers.length;
result = new bytes[](length);
unchecked {
for (uint256 i; i < length; i++) {
(address target, uint256 value, bytes calldata data) = LibERC7579.getExecution(pointers, i);
result[i] = execute(target, value, data);
}
}
}
function tryExecute(bytes32[] calldata pointers) internal returns (bytes[] memory result) {
uint256 length = pointers.length;
result = new bytes[](length);
unchecked {
for (uint256 i; i < length; i++) {
(address target, uint256 value, bytes calldata data) = LibERC7579.getExecution(pointers, i);
bool success;
(success, result[i]) = tryExecute(target, value, data);
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 getCallType(ExecMode mode) internal pure returns (CallType calltype) {
assembly {
calltype := mode
}
}
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.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: 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_7702 = ValidationType.wrap(0x00);
ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01);
ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02);
// --- Kernel Hook constants ---
address constant HOOK_MODULE_NOT_INSTALLED = address(0);
address constant HOOK_MODULE_INSTALLED = address(1);
address constant HOOK_ONLY_ENTRYPOINT = address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF);
// --- EIP7702 constants ---
bytes3 constant EIP7702_PREFIX = bytes3(0xef0100);
// --- 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;
bytes32 constant MAGIC_VALUE_SIG_REPLAYABLE = keccak256("kernel.replayable.signature");
// --- 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;
import {ValidationData, PermissionId, PassFlag} from "./Types.sol";
import {IPolicy} from "../interfaces/IERC7579Modules.sol";
struct Execution {
address target;
uint256 value;
bytes callData;
}
// === for internal usage ===
struct PermissionSigMemory {
uint8 idx;
uint256 length;
ValidationData validationData;
PermissionId permission;
PassFlag flag;
IPolicy policy;
bytes permSig;
address caller;
bytes32 digest;
}
struct PermissionDisableDataFormat {
bytes[] data;
}
struct PermissionEnableDataFormat {
bytes[] data;
}
struct UserOpSigEnableDataFormat {
bytes validatorData;
bytes hookData;
bytes selectorData;
bytes enableSig;
bytes userOpSig;
}
struct SelectorDataFormat {
bytes selectorInitData;
bytes hookInitData;
}
struct SelectorDataFormatWithExecutorData {
bytes selectorInitData;
bytes hookInitData;
bytes executorHookData;
}
struct InstallValidatorDataFormat {
bytes validatorData;
bytes hookData;
bytes selectorData;
}
struct InstallExecutorDataFormat {
bytes executorData;
bytes hookData;
}
struct InstallFallbackDataFormat {
bytes selectorData;
bytes hookData;
}// 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 {IHook, IFallback, IModule} from "../interfaces/IERC7579Modules.sol";
import {IERC7579Account} from "../interfaces/IERC7579Account.sol";
import {CallType} from "../types/Types.sol";
import {
SELECTOR_MANAGER_STORAGE_SLOT,
CALLTYPE_DELEGATECALL,
CALLTYPE_SINGLE,
MODULE_TYPE_FALLBACK
} from "../types/Constants.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 _clearSelectorData(bytes4 selector) internal returns (IHook hook, address target) {
SelectorConfig storage ss = _selectorConfig(selector);
hook = ss.hook;
ss.hook = IHook(address(0));
if (ss.callType == CALLTYPE_SINGLE) {
target = ss.target; // if callType!=CALLTYPE_SINGLE, don't need to call uninstall
}
ss.target = address(0);
ss.callType = CallType.wrap(bytes1(0x00));
}
}// 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)) || (hookData.length > 0 && bytes1(hookData[0]) == bytes1(0xff))) {
// if hook is not installed, it should call onInstall
// 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, IModule} from "../interfaces/IERC7579Modules.sol";
import {IERC7579Account} from "../interfaces/IERC7579Account.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);
if (executorData.length == 0) {
(bool success,) = address(executor).call(abi.encodeWithSelector(IModule.onInstall.selector, executorData)); // ignore return value
} else {
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 _clearExecutorData(IExecutor executor) internal returns (IHook hook) {
ExecutorConfig storage config = _executorConfig(executor);
hook = config.hook;
config.hook = IHook(address(0));
}
}// 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 {PackedUserOperation} from "../interfaces/PackedUserOperation.sol";
function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
assembly ("memory-safe") {
let mem := mload(0x40)
let len := data.length
calldatacopy(mem, data.offset, len)
ret := keccak256(mem, len)
}
}
function getSender(PackedUserOperation calldata userOp) pure returns (address) {
address data;
//read sender from userOp, which is first userOp member (saves 800 gas...)
assembly {
data := calldataload(userOp)
}
return address(uint160(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.4;
/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
/// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure.
/// This is for more safety by default.
/// Use the `tryRecover` variants if you need to get the zero address back
/// upon recovery failure instead.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
/// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
/// See: https://eips.ethereum.org/EIPS/eip-2098
/// This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT directly use signatures as unique identifiers:
/// - The recovery operations do NOT check if a signature is non-malleable.
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
/// EIP-712 also enables readable signing of typed data for better user safety.
/// - If you need a unique hash from a signature, please use the `canonicalHash` functions.
library ECDSA {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The order of the secp256k1 elliptic curve.
uint256 internal constant N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141;
/// @dev `N/2 + 1`. Used for checking the malleability of the signature.
uint256 private constant _HALF_N_PLUS_1 =
0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The signature is invalid.
error InvalidSignature();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RECOVERY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
} {
switch mload(signature)
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { continue }
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if returndatasize() { break }
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
} {
switch signature.length
case 64 {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
}
default { continue }
mstore(0x00, hash)
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if returndatasize() { break }
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* TRY-RECOVER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// WARNING!
// These functions will NOT revert upon recovery failure.
// Instead, they will return the zero address upon recovery failure.
// It is critical that the returned address is NEVER compared against
// a zero address (e.g. an uninitialized address variable).
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecover(bytes32 hash, bytes memory signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {} {
switch mload(signature)
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { break }
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
break
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {} {
switch signature.length
case 64 {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
}
default { break }
mstore(0x00, hash)
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
break
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an Ethereum Signed Message, created from a `hash`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
/// JSON-RPC method as part of EIP-191.
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, hash) // Store into scratch space for keccak256.
mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
}
}
/// @dev Returns an Ethereum Signed Message, created from `s`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
/// JSON-RPC method as part of EIP-191.
/// Note: Supports lengths of `s` up to 999999 bytes.
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let sLength := mload(s)
let o := 0x20
mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
mstore(0x00, 0x00)
// Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
for { let temp := sLength } 1 {} {
o := sub(o, 1)
mstore8(o, add(48, mod(temp, 10)))
temp := div(temp, 10)
if iszero(temp) { break }
}
let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
// Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
mstore(s, sLength) // Restore the length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CANONICAL HASH FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// The following functions returns the hash of the signature in it's canonicalized format,
// which is the 65-byte `abi.encodePacked(r, s, uint8(v))`, where `v` is either 27 or 28.
// If `s` is greater than `N / 2` then it will be converted to `N - s`
// and the `v` value will be flipped.
// If the signature has an invalid length, or if `v` is invalid,
// a uniquely corrupt hash will be returned.
// These functions are useful for "poor-mans-VRF".
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
let l := mload(signature)
for {} 1 {} {
mstore(0x00, mload(add(signature, 0x20))) // `r`.
let s := mload(add(signature, 0x40))
let v := mload(add(signature, 0x41))
if eq(l, 64) {
v := add(shr(255, s), 27)
s := shr(1, shl(1, s))
}
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
break
}
// If the length is neither 64 nor 65, return a uniquely corrupted hash.
if iszero(lt(sub(l, 64), 2)) {
// `bytes4(keccak256("InvalidSignatureLength"))`.
result := xor(keccak256(add(signature, 0x20), l), 0xd62f1ab2)
}
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHashCalldata(bytes calldata signature)
internal
pure
returns (bytes32 result)
{
// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
mstore(0x00, calldataload(signature.offset)) // `r`.
let s := calldataload(add(signature.offset, 0x20))
let v := calldataload(add(signature.offset, 0x21))
if eq(signature.length, 64) {
v := add(shr(255, s), 27)
s := shr(1, shl(1, s))
}
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
break
}
// If the length is neither 64 nor 65, return a uniquely corrupted hash.
if iszero(lt(sub(signature.length, 64), 2)) {
calldatacopy(mload(0x40), signature.offset, signature.length)
// `bytes4(keccak256("InvalidSignatureLength"))`.
result := xor(keccak256(mload(0x40), signature.length), 0xd62f1ab2)
}
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
let v := add(shr(255, vs), 27)
let s := shr(1, shl(1, vs))
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes.
function emptySignature() internal pure returns (bytes calldata signature) {
/// @solidity memory-safe-assembly
assembly {
signature.length := 0
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for handling ERC7579 mode and execution data.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/accounts/LibERC7579.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/main/contracts/account/utils/draft-ERC7579Utils.sol)
library LibERC7579 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cannot decode `executionData`.
error DecodingError();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A single execution.
bytes1 internal constant CALLTYPE_SINGLE = 0x00;
/// @dev A batch of executions.
bytes1 internal constant CALLTYPE_BATCH = 0x01;
/// @dev A `delegatecall` execution.
bytes1 internal constant CALLTYPE_DELEGATECALL = 0xff;
/// @dev Default execution type that reverts on failure.
bytes1 internal constant EXECTYPE_DEFAULT = 0x00;
/// @dev Execution type that does not revert on failure.
bytes1 internal constant EXECTYPE_TRY = 0x01;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Encodes the fields into a mode.
function encodeMode(bytes1 callType, bytes1 execType, bytes4 selector, bytes22 payload)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, callType)
mstore(0x01, execType)
mstore(0x02, selector)
mstore(0x06, 0)
mstore(0x0a, payload)
result := mload(0x00)
}
}
/// @dev Returns the call type of the mode.
function getCallType(bytes32 mode) internal pure returns (bytes1) {
return bytes1(mode);
}
/// @dev Returns the call type of the mode.
function getExecType(bytes32 mode) internal pure returns (bytes1) {
return mode[1];
}
/// @dev Returns the selector of the mode.
function getSelector(bytes32 mode) internal pure returns (bytes4) {
return bytes4(bytes32(uint256(mode) << 16));
}
/// @dev Returns the payload stored in the mode.
function getPayload(bytes32 mode) internal pure returns (bytes22) {
return bytes22(bytes32(uint256(mode) << 80));
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EXECUTION DATA OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Decodes a single call execution.
/// Reverts if `executionData` is not correctly encoded.
function decodeSingle(bytes calldata executionData)
internal
pure
returns (address target, uint256 value, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
if iszero(gt(executionData.length, 0x33)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
target := shr(96, calldataload(executionData.offset))
value := calldataload(add(executionData.offset, 0x14))
data.offset := add(executionData.offset, 0x34)
data.length := sub(executionData.length, 0x34)
}
}
/// @dev Decodes a single call execution without bounds checks.
function decodeSingleUnchecked(bytes calldata executionData)
internal
pure
returns (address target, uint256 value, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
target := shr(96, calldataload(executionData.offset))
value := calldataload(add(executionData.offset, 0x14))
data.offset := add(executionData.offset, 0x34)
data.length := sub(executionData.length, 0x34)
}
}
/// @dev Decodes a single delegate execution.
/// Reverts if `executionData` is not correctly encoded.
function decodeDelegate(bytes calldata executionData)
internal
pure
returns (address target, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
if iszero(gt(executionData.length, 0x13)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
target := shr(96, calldataload(executionData.offset))
data.offset := add(executionData.offset, 0x14)
data.length := sub(executionData.length, 0x14)
}
}
/// @dev Decodes a single delegate execution without bounds checks.
function decodeDelegateUnchecked(bytes calldata executionData)
internal
pure
returns (address target, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
target := shr(96, calldataload(executionData.offset))
data.offset := add(executionData.offset, 0x14)
data.length := sub(executionData.length, 0x14)
}
}
/// @dev Decodes a batch.
/// Reverts if `executionData` is not correctly encoded.
function decodeBatch(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers)
{
/// @solidity memory-safe-assembly
assembly {
let u := calldataload(executionData.offset)
if or(shr(64, u), gt(0x20, executionData.length)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
pointers.offset := add(add(executionData.offset, u), 0x20)
pointers.length := calldataload(add(executionData.offset, u))
if pointers.length {
let e := sub(add(executionData.offset, executionData.length), 0x20)
// Perform bounds checks on the decoded `pointers`.
// Does an out-of-gas revert.
for { let i := pointers.length } 1 {} {
i := sub(i, 1)
let p := calldataload(add(pointers.offset, shl(5, i)))
let c := add(pointers.offset, p)
let q := calldataload(add(c, 0x40))
let o := add(c, q)
// forgefmt: disable-next-item
if or(shr(64, or(calldataload(o), or(p, q))),
or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
if iszero(i) { break }
}
}
}
}
/// @dev Decodes a batch without bounds checks.
/// This function can be used in `execute`, if the validation phase has already
/// decoded the `executionData` with checks via `decodeBatch`.
function decodeBatchUnchecked(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers)
{
/// @solidity memory-safe-assembly
assembly {
let o := add(executionData.offset, calldataload(executionData.offset))
pointers.offset := add(o, 0x20)
pointers.length := calldataload(o)
}
}
/// @dev Decodes a batch and optional `opData`.
/// Reverts if `executionData` is not correctly encoded.
function decodeBatchAndOpData(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers, bytes calldata opData)
{
opData = emptyCalldataBytes();
pointers = decodeBatch(executionData);
if (hasOpData(executionData)) {
/// @solidity memory-safe-assembly
assembly {
let e := sub(add(executionData.offset, executionData.length), 0x20)
let p := calldataload(add(0x20, executionData.offset))
let q := add(executionData.offset, p)
opData.offset := add(q, 0x20)
opData.length := calldataload(q)
if or(shr(64, or(opData.length, p)), gt(add(q, opData.length), e)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Decodes a batch without bounds checks.
/// This function can be used in `execute`, if the validation phase has already
/// decoded the `executionData` with checks via `decodeBatchAndOpData`.
function decodeBatchAndOpDataUnchecked(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers, bytes calldata opData)
{
opData = emptyCalldataBytes();
pointers = decodeBatchUnchecked(executionData);
if (hasOpData(executionData)) {
/// @solidity memory-safe-assembly
assembly {
let q := add(executionData.offset, calldataload(add(0x20, executionData.offset)))
opData.offset := add(q, 0x20)
opData.length := calldataload(q)
}
}
}
/// @dev Returns whether the `executionData` has optional `opData`.
function hasOpData(bytes calldata executionData) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result :=
iszero(or(lt(executionData.length, 0x40), lt(calldataload(executionData.offset), 0x40)))
}
}
/// @dev Returns the `i`th execution at `pointers`, without bounds checks.
/// The bounds check is excluded as this function is intended to be called in a bounded loop.
function getExecution(bytes32[] calldata pointers, uint256 i)
internal
pure
returns (address target, uint256 value, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
let c := add(pointers.offset, calldataload(add(pointers.offset, shl(5, i))))
target := calldataload(c)
value := calldataload(add(c, 0x20))
let o := add(c, calldataload(add(c, 0x40)))
data.offset := add(o, 0x20)
data.length := calldataload(o)
}
}
/// @dev Reencodes `executionData` such that it has `opData` added to it.
/// Like `abi.encode(abi.decode(executionData, (Call[])), opData)`.
/// Useful for forwarding `executionData` with extra `opData`.
/// This function does not perform any check on the validity of `executionData`.
function reencodeBatch(bytes calldata executionData, bytes memory opData)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := add(0x64, mload(0x40)) // Give some space for `reencodeBatchAsExecuteCalldata`.
let s := calldataload(executionData.offset) // Offset of `calls`.
let n := sub(executionData.length, s) // Byte length of `calls`.
mstore(add(result, 0x20), 0x40) // Store the new offset of `calls`.
calldatacopy(add(result, 0x60), add(executionData.offset, s), n)
mstore(add(result, 0x40), add(0x40, n)) // Store the new offset of `opData`.
let o := add(add(result, 0x60), n) // Start offset of `opData` destination in memory.
let d := sub(opData, o) // Offset difference between `opData` source and `o`.
let end := add(mload(opData), add(0x20, o)) // End of `opData` destination in memory.
for {} 1 {} {
mstore(o, mload(add(o, d)))
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(result, sub(o, add(result, 0x20))) // Store the length of `result`.
calldatacopy(end, calldatasize(), 0x40) // Zeroize the bytes after `end`.
mstore(0x40, add(0x20, o)) // Allocate memory.
}
}
/// @dev `abi.encodeWithSignature("execute(bytes32,bytes)", mode, reencodeBatch(executionData, opData))`.
function reencodeBatchAsExecuteCalldata(
bytes32 mode,
bytes calldata executionData,
bytes memory opData
) internal pure returns (bytes memory result) {
result = reencodeBatch(executionData, opData);
/// @solidity memory-safe-assembly
assembly {
let n := mload(result)
result := sub(result, 0x64)
mstore(add(result, 0x44), 0x40) // Offset of `executionData`.
mstore(add(result, 0x24), mode)
mstore(add(result, 0x04), 0xe9ae5c53) // `execute(bytes32,bytes)`.
mstore(result, add(0x64, n))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Helper function to return empty calldata bytes.
function emptyCalldataBytes() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.offset := 0
result.length := 0
}
}
}{
"remappings": [
"ExcessivelySafeCall/=lib/ExcessivelySafeCall/src/",
"forge-std/=lib/forge-std/src/",
"solady/=lib/solady/src/",
"solady_test/=lib/solady/test/",
"@openzeppelin/contracts/=lib/p256-verifier/lib/openzeppelin-contracts/contracts/",
"FreshCryptoLib/=lib/FreshCryptoLib/solidity/src/",
"I4337/=lib/I4337/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/p256-verifier/lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts/=lib/p256-verifier/lib/openzeppelin-contracts/",
"p256-verifier/=lib/p256-verifier/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IEntryPoint","name":"_entrypoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"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":"InvalidSelectorData","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":"vId","type":"bytes21"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bool","name":"allow","type":"bool"}],"name":"grantAccess","outputs":[],"stateMutability":"payable","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":"data","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":[{"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":"address","name":"entryPoint","type":"address"}],"name":"replayableUserOpHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","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
610140806040523461020a576020816161db8038038091610020828561020e565b83398101031261020a57516001600160a01b038116810361020a57306080524660a05260a060405161005360408261020e565b6006815260208101906512d95c9b995b60d21b82526040519161007760408461020e565b60058352602083019164302e332e3360d81b8352519020915190208160c0528060e052604051917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f835260208301526040820152466060820152306080820152206101005261012052604051602081019063deadbeef60e01b82526004815261010160248261020e565b5190516001600160581b031981169190601582106101ea575b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f80546001600160a81b031916605885901c179055604051615f9590816102468239608051816156fb015260a0518161571e015260c0518161578e015260e051816157b4015261010051816156da0152610120518181816103c4015281816106ac0152818161086601528181610ac401528181610e600152818161115d015281816112ee0152818161132901528181611528015281816119b901528181611aeb015281816125b901526132050152f35b6001600160581b031960159290920360031b82901b161690505f8061011a565b5f80fd5b601f909101601f19168101906001600160401b0382119082101761023157604052565b634e487b7160e01b5f52604160045260245ffdfe6080604052600436101561001d575b366131ab5761001b61317a565b005b5f3560e01c8063112d3a7d1461021c578063150b7a02146102175780631626ba7e1461021257806319822f7c1461020d5780631f1b92e3146102085780633659cfe6146102035780633c3b752b146101fe57806352141cd9146101f957806357b3a5f4146101f45780636e6fa0c6146101ef578063721e67f4146101ea57806384b0196e146101e55780638dd7712f146101e057806390ef8862146101db5780639198bdf5146101d65780639517e29f146101d15780639cfd7cff146101cc578063a65d69d4146101c7578063a71763a8146101c2578063adb610a3146101bd578063b8afe17d146101b8578063b9b82941146101b3578063bc197c81146101ae578063c3e58978146101a9578063d03c7914146101a4578063d691c9641461019f578063e6f3d50a1461019a578063e9ae5c5314610195578063f1f7f0f914610190578063f23a6e611461018b578063f2dc691d146101865763fc9c5dec0361000e57611cc0565b611c9f565b611c45565b611c0f565b611adf565b61195f565b61187d565b611830565b61175d565b61164c565b6114f5565b61147f565b61144d565b61131d565b6112d9565b611281565b611151565b61103a565b610f2b565b610e30565b610d92565b610d0c565b610cb1565b610bfe565b610a5e565b6109c8565b61084b565b610695565b610390565b61032f565b6102d5565b6102af565b6001600160a01b0381160361023257565b5f80fd5b359061024182610221565b565b9181601f84011215610232578235916001600160401b038311610232576020838186019501011161023257565b6060600319820112610232576004359160243561028c81610221565b91604435906001600160401b038211610232576102ab91600401610243565b9091565b346102325760206102cb6102c236610270565b92919091611f13565b6040519015158152f35b34610232576080366003190112610232576102f1600435610221565b6102fc602435610221565b6064356001600160401b0381116102325761031b903690600401610243565b5050604051630a85bd0160e11b8152602090f35b34610232576040366003190112610232576004356024356001600160401b0381116102325760209161036861036e923690600401610243565b91613377565b6040516001600160e01b03199091168152f35b90816101209103126102325790565b6060366003190112610232576004356001600160401b038111610232576103bb903690600401610381565b602435604435917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303610662576103ff60208201356135c3565b9092919084836001600160f81b0319861615610649575b8261042193946137bc565b9361044661043661043184611ea5565b611fdd565b946001600160f81b031916151590565b938480610608575b6105f957602001516001600160a01b0316801591819083806105f2575b6104f2576001926104866104a5925f525f60205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b149081156105ea575b501561055d5782610501575b50506104f257816104dc925b6104e0575b506040519081529081906020820190565b0390f35b3490349034903490335af1505f6104cb565b631a0a9b9f60e21b5f5260045ffd5b61055692506105529161053661053061052a61051f61054b95611edc565b936060810190612009565b90611d20565b90611e6f565b63ffffffff60e01b165f5260205260405f2090565b5460ff1690565b1590565b5f806104ba565b829192916105b7575b506104f25761052a81606061057c930190612009565b638dd7712f60e01b916001600160e01b03199161059891611e6f565b16036105a857816104dc926104c6565b63dbbb044b60e01b5f5260045ffd5b6105e4915061054b6105cb61055292611edc565b6105366105306105de6060880188612009565b90611d0f565b5f610566565b90505f6104ae565b508661046b565b633ab3447f60e11b5f5260045ffd5b50805163ffffffff1663ffffffff6106416106385f516020615f755f395f51905f525463ffffffff9060c81c1690565b63ffffffff1690565b91161061044e565b5f516020615f755f395f51905f525460581b9250610416565b6348f5c3ed60e01b5f5260045ffd5b6004359063ffffffff8216820361023257565b359063ffffffff8216820361023257565b6020366003190112610232576106a9610671565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580610841575b15610838576107116107056106ff5f516020615f755f395f51905f525460581b90565b60581c90565b6001600160a01b031690565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91610809575b50156106625760405163d68f602560e01b8152916001600160a01b0391909116905f838061076e36343360048501612167565b038183865af19283156107dc575f936107e1575b5061078c90613a50565b803b1561023257604051630b9dfbed60e11b8152915f9183918290849082906107b890600483016121b0565b03925af180156107dc576107c857005b806107d65f61001b93610fe3565b80610d64565b6120bf565b61078c919350610802903d805f833e6107fa8183610fe3565b8101906120e5565b9290610782565b61082b915060203d602011610831575b6108238183610fe3565b8101906120a7565b5f61073b565b503d610819565b61001b90613a50565b50303314156106dc565b60203660031901126102325760043561086381610221565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614158061097c575b15610973576108b96107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91610954575b50156106625760405163d68f602560e01b8152916001600160a01b0391909116905f838061091636343360048501612167565b038183865af19283156107dc575f93610934575b5061078c906121c1565b61078c91935061094d903d805f833e6107fa8183610fe3565b929061092a565b61096d915060203d602011610831576108238183610fe3565b5f6108e3565b61001b906121c1565b5030331415610896565b6001600160581b031981160361023257565b9181601f84011215610232578235916001600160401b038311610232576020808501948460051b01011161023257565b346102325760a0366003190112610232576004356109e581610986565b6024356109f181610221565b6044356001600160401b03811161023257610a10903690600401610243565b6064939193356001600160401b03811161023257610a32903690600401610243565b91608435956001600160401b03871161023257610a5661001b973690600401610998565b969095612327565b608036600319011261023257600435610a7681610986565b602435610a8281610221565b6044356001600160401b03811161023257610aa1903690600401610243565b6064356001600160401b03811161023257610ac0903690600401610243565b91337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580610be2575b15610bd457610b176107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91610bb5575b50156106625760405163d68f602560e01b8152956001600160a01b039190911694905f8780610b7536343360048501612167565b0381838a5af19687156107dc575f97610b95575b5061078c9596976124aa565b61078c969750610bae903d805f833e6107fa8183610fe3565b9695610b89565b610bce915060203d602011610831576108238183610fe3565b5f610b41565b919361001b959391936124aa565b5030331415610af4565b6001600160e01b031981160361023257565b34610232576020366003190112610232576104dc610c3f600435610c2181610bec565b5f60408051610c2f81610f71565b828152826020820152015261203b565b600160405191610c4e83610f71565b805460a083901b839003168084529101546001600160a01b0380821660208086019182526001600160f81b031960589490941b84166040968701908152865195841686529151909216918401919091525116918101919091529081906060820190565b3461023257604036600319011261023257602060ff610d00600435610cd581610986565b610cea60243591610ce583610bec565b611edc565b9063ffffffff60e01b165f5260205260405f2090565b54166040519015158152f35b34610232576020366003190112610232576020610d41600435610d2e81610221565b5f604051610d3b81610f91565b5261332a565b60405190610d4e82610f91565b546001600160a01b031690819052604051908152f35b5f91031261023257565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610232575f36600319011261023257610dd1610ddf610db0613d9c565b604092919251938493600f60f81b855260e0602086015260e0850190610d6e565b908382036040850152610d6e565b4660608301523060808301525f60a083015281810360c083015260206060519182815201906080905f5b818110610e17575050500390f35b8251845285945060209384019390920191600101610e09565b6040366003190112610232576004356001600160401b03811161023257610e5b903690600401610381565b6024357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303610662575f908152602081905260409020546001600160a01b03169060609060018314159081610efb575b610ed0610ec9826060610ed7940190612009565b8091611d2e565b9030613e84565b5015610eec57610ee357005b61001b91613ea9565b63f21e646b60e01b5f5260045ffd5b9150610ed7610ed0610ec9610f21610f19610ec96060880188612009565b903489613e39565b9492505050610eb5565b34610232575f36600319011261023257602063ffffffff5f516020615f755f395f51905f525460c81c16604051908152f35b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b03821117610f8c57604052565b610f5d565b602081019081106001600160401b03821117610f8c57604052565b604081019081106001600160401b03821117610f8c57604052565b61012081019081106001600160401b03821117610f8c57604052565b90601f801991011681019081106001600160401b03821117610f8c57604052565b60405190610241604083610fe3565b6040519061024161012083610fe3565b6001600160401b038111610f8c5760051b60200190565b6080366003190112610232576004356001600160401b03811161023257611065903690600401610998565b602435916001600160401b038311610232573660238401121561023257826004013561109081611023565b9361109e6040519586610fe3565b8185526024602086019260061b8201019036821161023257602401915b818310611110575050506044356001600160401b038111610232576110e4903690600401610998565b90606435946001600160401b0386116102325761110861001b963690600401610998565b9590946125af565b604083360312610232576020604091825161112a81610fac565b61113386610684565b81528286013561114281610221565b838201528152019201916110bb565b61115a36610270565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580611277575b1561126d576111b06107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f9161124e575b50156106625760405163d68f602560e01b8152936001600160a01b039190911692905f858061120e36343360048501612167565b038183885af19485156107dc575f9561122e575b5061078c93949561277e565b61078c949550611247903d805f833e6107fa8183610fe3565b9493611222565b611267915060203d602011610831576108238183610fe3565b5f6111da565b9161001b9361277e565b503033141561118d565b34610232575f366003190112610232576104dc6040516112a2604082610fe3565b60168152756b65726e656c2e616476616e6365642e76302e332e3360501b6020820152604051918291602083526020830190610d6e565b34610232575f366003190112610232576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b61132636610270565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580611443575b156114395761137c6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f9161141a575b50156106625760405163d68f602560e01b8152936001600160a01b039190911692905f85806113da36343360048501612167565b038183885af19485156107dc575f956113fa575b5061078c939495612ad2565b61078c949550611413903d805f833e6107fa8183610fe3565b94936113ee565b611433915060203d602011610831576108238183610fe3565b5f6113a6565b9161001b93612ad2565b5030331415611359565b34610232575f36600319011261023257602063ffffffff5f516020615f755f395f51905f525460a81c16604051908152f35b346102325760203660031901126102325760406114af6004356114a181610986565b6114a9612cfc565b50611ea5565b8151906114bb82610fac565b5463ffffffff81168083526001600160a01b03602092831c81169383019384528451918252925190921690820152f35b8015150361023257565b60603660031901126102325760043561150d81610986565b60243561151981610bec565b604435611525816114eb565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580611642575b156116385761157b6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91611619575b50156106625760405163d68f602560e01b8152926001600160a01b039190911691905f84806115d936343360048501612167565b038183875af19384156107dc575f946115f9575b5061078c929394614356565b61078c939450611612903d805f833e6107fa8183610fe3565b93926115ed565b611632915060203d602011610831576108238183610fe3565b5f6115a5565b9061001b92614356565b5030331415611558565b346102325760a036600319011261023257611668600435610221565b611673602435610221565b6044356001600160401b03811161023257611692903690600401610998565b50506064356001600160401b038111610232576116b3903690600401610998565b50506084356001600160401b038111610232576116d4903690600401610243565b505060405163bc197c8160e01b8152602090f35b602080825282516001600160f01b03191681830152808301516001600160a01b03166040808401919091529092015160608083015280516080830181905260a09092019201905f5b81811061173d5750505090565b82516001600160501b031916845260209384019390920191600101611730565b346102325760203660031901126102325761179c60043561177d81610bec565b60606040805161178c81610f71565b5f81525f60208201520152612071565b6001604051916117ab83610f71565b805461ffff60f01b8160f01b168452828060a01b039060101c16602084015201906040519182602082549182815201915f5260205f20905f5b81811061180d576104dc85876117fc81880382610fe3565b6040820152604051918291826116e8565b825460501b6001600160501b0319168452602090930192600192830192016117e4565b346102325760203660031901126102325760206102cb600435612d14565b9060406003198301126102325760043591602435906001600160401b038211610232576102ab91600401610243565b6118863661184e565b90916001600160a01b036118993361332a565b54169182156119505760609060018414159485611939575b6118bb92936145dc565b92611929575b50506040518091602082016020835281518091526040830190602060408260051b8601019301915f905b8282106118fa57505050500390f35b919360019193955060206119198192603f198a82030186528851610d6e565b96019201920185949391926118eb565b61193291613ea9565b5f806118c1565b6118bb9250611949363487613de0565b92506118b1565b63710c949760e01b5f5260045ffd5b60603660031901126102325760043561197781610986565b6024356001600160401b03811161023257611996903690600401610243565b6044356001600160401b038111610232576119b5903690600401610243565b90337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580611ad5575b15611ac957611a0c6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91611aaa575b50156106625760405163d68f602560e01b8152946001600160a01b039190911693905f8680611a6a36343360048501612167565b038183895af19586156107dc575f96611a8a575b5061078c949596612dec565b61078c959650611aa3903d805f833e6107fa8183610fe3565b9594611a7e565b611ac3915060203d602011610831576108238183610fe3565b5f611a36565b91909261001b94612dec565b50303314156119e9565b611ae83661184e565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580611c05575b15611bfb57611b3e6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91611bdc575b50156106625760405163d68f602560e01b8152926001600160a01b039190911691905f8480611b9c36343360048501612167565b038183875af19384156107dc575f94611bbc575b5061078c92939461307f565b61078c939450611bd5903d805f833e6107fa8183610fe3565b9392611bb0565b611bf5915060203d602011610831576108238183610fe3565b5f611b68565b9061001b9261307f565b5030331415611b1b565b34610232575f3660031901126102325760205f516020615f755f395f51905f525460581b604051906001600160581b0319168152f35b346102325760a036600319011261023257611c61600435610221565b611c6c602435610221565b6084356001600160401b03811161023257611c8b903690600401610243565b505060405163f23a6e6160e01b8152602090f35b34610232576020366003190112610232576020600435600760405191108152f35b34610232576040366003190112610232576004356001600160401b03811161023257611d07611cf56020923690600401610381565b60243590611d0282610221565b61308a565b604051908152f35b906008116102325760040190600490565b906004116102325790600490565b909291928360041161023257831161023257600401916003190190565b906018116102325760040190601490565b906014116102325790601490565b906020116102325790602090565b90929192836020116102325783116102325760200191601f190190565b909291928360011161023257831161023257600101915f190190565b906009116102325760010190600890565b909291928360091161023257831161023257600901916008190190565b906016116102325790601690565b906016116102325760020190601490565b909291928360161161023257831161023257601601916015190190565b906002116102325790600290565b909291928360141161023257831161023257601401916013190190565b90602c116102325760180190601490565b90939293848311610232578411610232578101920390565b356001600160e01b0319811692919060048210611e8a575050565b6001600160e01b031960049290920360031b82901b16169150565b6001600160581b0319165f527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f85060205260405f2090565b6001600160581b0319165f527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f85160205260405f2090565b90929060018103611f6257506001600160a01b0392611f5c9250611f4c915060581b600160581b600160f81b0316600160f81b17611ea5565b5460201c6001600160a01b031690565b16151590565b60028103611f9657506001600160a01b0392611f5c92506107059150611f8990841661332a565b546001600160a01b031690565b600303611fd657611fb7611fb2610530600193611fc595611d20565b61203b565b01546001600160a01b031690565b6001600160a01b0390811691161490565b5050505f90565b90604051611fea81610fac565b915463ffffffff81168352602090811c6001600160a01b031690830152565b903590601e198136030182121561023257018035906001600160401b0382116102325760200191813603831361023257565b63ffffffff60e01b165f527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b60205260405f2090565b63ffffffff60e01b165f527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f85260205260405f2090565b9081602091031261023257516120bc816114eb565b90565b6040513d5f823e3d90fd5b6001600160401b038111610f8c57601f01601f191660200190565b602081830312610232578051906001600160401b038211610232570181601f8201121561023257805190612118826120ca565b926121266040519485610fe3565b8284526020838301011161023257815f9260208093018386015e8301015290565b908060209392818452848401375f828201840152601f01601f1916010190565b6120bc939260609260018060a01b03168252602082015281604082015201905f612147565b6120bc949260609260018060a01b0316825260208201528160408201520191612147565b9060206120bc928181520190610d6e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8190556001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2565b60405190612223602083610fe3565b5f8252565b90813b5f612235826120ca565b936122436040519586610fe3565b82855260208501903c565b80516020909101516001600160e81b0319811692919060038210612270575050565b6001600160e81b0319600392830390921b82901b16169150565b5f516020615f755f395f51905f52805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b634e487b7160e01b5f52603260045260245ffd5b908210156122e6576102ab9160051b810190612009565b6122bb565b908092918237015f815290565b3d15612322573d90612309826120ca565b916123176040519384610fe3565b82523d5f602084013e565b606090565b94939291909695966001600160581b03196123606123535f516020615f755f395f51905f525460581b90565b6001600160581b03191690565b1615801590612482575b612474576001600160581b03198616156104f2576001600160f81b03198616600160f81b14158061245c575b61244d57856123a76123f497613b15565b6123c86123b2611004565b60018152925b6001600160a01b03166020840152565b5f516020615f755f395f51905f52805463ffffffff60a81b1916600160a81b179055613b7b565b613b7b565b5f5b81811061240257505050565b5f8061240f8385876122cf565b9061241f604051809381936122eb565b039082305af161242d6122f8565b501561243b576001016123f6565b636534eae560e11b5f5260045260245ffd5b6361c4e91b60e11b5f5260045ffd5b506001600160f81b03198616600160f91b1415612396565b62dc149f60e41b5f5260045ffd5b5061ef0160f01b6001600160e81b03196124a361249e30612228565b61224e565b161461236a565b94939291906001600160581b03198616156104f2576001600160f81b03198616600160f81b141580612555575b61244d576124e486613b15565b6001600160a01b036124f8611f4c88611ea5565b1615612507575b505050505050565b61254a956123ef61252d5f516020615f755f395f51905f525463ffffffff9060a81c1690565b926123b860405194612540604087610fe3565b63ffffffff168552565b5f80808080806124ff565b506001600160f81b03198616600160f91b14156124d7565b9060405161257a81610f71565b82546001600160a01b03908116825260019390930154928316602082015260589290921b6001600160f81b0319166040830152565b95909491939092337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141580612723575b156127155761260c6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f916126f6575b50156106625760405163d68f602560e01b8152966001600160a01b039190911695905f888061266a36343360048501612167565b0381838b5af19788156107dc575f986126d6575b5061268a969798613f22565b803b1561023257604051630b9dfbed60e11b8152915f9183918290849082906126b690600483016121b0565b03925af180156107dc576126c8575b50565b806107d65f61024193610fe3565b61268a9798506126ef903d805f833e6107fa8183610fe3565b979661267e565b61270f915060203d602011610831576108238183610fe3565b5f612636565b919390929461024196613f22565b50303314156125e9565b9160206120bc938181520191612147565b356bffffffffffffffffffffffff1981169291906014821061275e575050565b6bffffffffffffffffffffffff1960149290920360031b82901b16169150565b9091600182036128fa575f516020615f355f395f51905f5293906054600160f81b600160581b600160f81b03605887901b1617916127c86127be84611ea5565b5463ffffffff1690565b5f516020615f755f395f51905f525460a81c63ffffffff169063ffffffff8083169116146128e2575b5061285a61283361070561282d6128276128205f516020615f755f395f51905f525463ffffffff9060a81c1690565b9886611d5c565b9061273e565b60601c90565b61284a61283e611004565b63ffffffff9097168752565b6001600160a01b03166020860152565b612885601482019461286c8680612009565b61287c6034869493940189612009565b93909288613b7b565b019160046128938483612009565b9050146128c1575b5050505b604080519182526001600160a01b03909216602082015290819081015b0390a1565b61053061052a6128da946128d493612009565b906142f1565b5f808061289b565b6128f49060010163ffffffff1661228a565b5f6127f1565b6002820361296257806129575f516020615f355f395f51905f5295603461293161070561282d612827601461295d99019588611d5c565b93612950856129408580612009565b906001600160a01b038c16614267565b0190612009565b91614117565b61289f565b600382036129d857806129575f516020615f355f395f51905f529560386129d061070561282d612827601861295d9901956129ca8c8a6129b861070561282d612827876129b26105308288611d20565b95611d4b565b6129c28b80612009565b939092613f8f565b88611d4b565b930190612009565b600482148015612a76575b8015612a6c575b15612a5d576001600160a01b03831693843b1561023257612a24945f92836040518098819582946306d61fe760e41b84526004840161272d565b03925af19283156107dc575f516020615f355f395f51905f5293612a49575b5061289f565b806107d65f612a5793610fe3565b5f612a43565b631092ef5760e11b5f5260045ffd5b50600682146129ea565b50600582146129e3565b359060208110612a8e575090565b5f199060200360031b1b1690565b929192612aa8826120ca565b91612ab66040519384610fe3565b829481845281830111610232578281602093845f960137010152565b909160018203612b43575f516020615f555f395f51905f5293612b2191612b1b91612b12600160f81b600160581b600160f81b03605889901b1617614424565b505b3691612a9c565b83614484565b50604080519182526001600160a01b03909216602082015290819081016128bc565b60028203612bb3576001600160a01b038381165f9081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902080546001600160a01b031981169091555f516020615f555f395f51905f5295612b2193612b1b939092165b50612b14565b919060038103612bd8575050610530612bd492612bcf92611d20565b6143c0565b5050565b909160048203612c6157612b1b612b21915f516020615f555f395f51905f5295612c105f516020615f755f395f51905f525460581b90565b612c1c611f4c82611ea5565b6001600160a01b03888116911614612c345750612b14565b612c40612c5b91611ea5565b8054640100000000600160c01b031916640100000000179055565b5f612bad565b600582148015612cf2575b15612a5d575f516020615f755f395f51905f525460581b612c96612c908684611d6a565b90612a80565b906001600160f81b03198116600160f91b14612cca575b5050612b1b612b21915f516020615f555f395f51905f5295612b14565b60081b6001600160e01b03191614612ce3575f80612cad565b6313002bdd60e31b5f5260045ffd5b5060068214612c6c565b60405190612d0982610fac565b5f6020838281520152565b612d28818060081b918160301b9160501b90565b929091906001600160f81b03198116600160f81b14159081612dd8575b81612dc3575b81612daa575b50611fd65760ff60f81b16600160f81b8114159081612da0575b50612d9a576001600160e01b031916612d95576001600160501b031916612d9157600190565b5f90565b505f90565b50505f90565b905015155f612d6b565b6001600160f81b031916607f60f91b141590505f612d51565b6001600160f81b031980821614159150612d4b565b6001600160f81b0319811615159150612d45565b9094939291612dfa82614424565b916001600160f81b03198116600160f81b03612e72575f516020615f555f395f51905f5291612e48612e426102419899612e6a9460018060a01b039060581c16933691612a9c565b82614484565b5060408051600181526001600160a01b03909216602083015290918291820190565b0390a161488a565b9294919290506001600160f81b03198116600160f91b0361244d5760081b92612e9a84612071565b94612ea587806147fb565b94905060018701946001865401036130705794956001600160e01b0319871695905f5b8654811015612f7e57805f516020615f555f395f51905f52612f758c612f53612f45612e428e612f338f99612f2d612f1d612f15612f088460019f614830565b90549060031b1c60501b90565b908160501c90565b90508c8060a01b031697806147fb565b906122cf565b60409491945194859360208501614845565b03601f198101835282610fe3565b5060408051600581526001600160a01b03909216602083015290918291820190565b0390a101612ec8565b509194509296612ff961300c9161300761306b9598612faa6001612fa46102419d612071565b0161485a565b8554612fe790612fc59060101c6001600160a01b0316610705565b93612fdc612fd382806147fb565b919092806147fb565b5f19019290506122cf565b60409591955195869360208501614845565b03601f198101845283610fe3565b614484565b5080545f516020615f555f395f51905f5290613058906130379060101c6001600160a01b0316610705565b60408051600681526001600160a01b03909216602083015290918291820190565b0390a180546001600160b01b0319169055565b61488a565b63013dcc8d60e31b5f5260045ffd5b906126c592916145dc565b612f4590613174906130a56001600160a01b03823516610705565b906131466020820135612f456130c76130c16040860186612009565b90614915565b936130d86130c16060830183612009565b90608081013560a0820135906130fa6130c160c08501359460e0810190612009565b93604051988997602089019b8c94919260e0969399989794919961010087019a60018060a01b03168752602087015260408601526060850152608084015260a083015260c08201520152565b51902060408051602081019283526001600160a01b03909516908501525f6060850152929182906080820190565b51902090565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460408051338152346020820152a1565b6131c76131c25f356001600160e01b03191661203b565b61256d565b80516001600160a01b03906131dd908216610705565b161561331b5780516060906001600160a01b0316806002600160a01b031981016132f95750507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303610662575b60408201516001600160f81b031916806132b957506020820151613260906001600160a01b0316614920565b92905b156132b157516001600160a01b0316906001821415828161329d575b5061328d575b825160208401f35b61329691613ea9565b5f80613285565b6001600160a01b039150811614155f61327f565b825160208401fd5b6001600160f81b0319908116036132ea5760208201516132e3906001600160a01b03163690613e5f565b9290613263565b632d6a6bb760e01b5f5260045ffd5b600103613307575b50613234565b613315915036903490613de0565b5f613301565b631cd4b64760e21b5f5260045ffd5b6001600160a01b03165f9081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b9081602091031261023257516120bc81610bec565b9161338191614962565b919080836001600160f81b03198416156135a3575b6020811015918261356c575b82613556575b50506133b661043184611ea5565b60208101516001600160a01b03906133cf908216610705565b161580613543575b6104f2576001600160f81b031984161515908161350a575b506105f9576001600160f81b03198316600160f81b03613483579061341b6020949392613439966149b4565b604051637aa8f17760e11b815295869485938493336004860161218c565b039160581c6001600160a01b03165afa9081156107dc575f9161345a575090565b6120bc915060203d60201161347c575b6134748183610fe3565b810190613362565b503d61346a565b92916001600160f81b03198116600160f91b036134e35760081b93600160f11b6134c66134b96134b288612071565b5460f01b90565b6001600160f01b03191690565b166134d4576120bc94614af2565b635b71057960e01b5f5260045ffd5b929391929091906001600160f81b03191661244d576120bc93613505916149b4565b614a0e565b5163ffffffff16905063ffffffff61353a6106385f516020615f755f395f51905f525463ffffffff9060c81c1690565b9116105f6133ef565b506001600160f81b0319841615156133d7565b819295506135649350611d78565b925f806133a8565b91507f0555ad2729e8da1777a4e5020806f8bf7601c3db6bfe402f410a34958363a95a61359c612c908385611d6a565b14916133a2565b92506135bd5f516020615f755f395f51905f525460581b90565b92613396565b90818060081b9160ff839260f01c166002146135db57565b6001600160d81b031983169150565b9080601f83011215610232578160206120bc93359101612a9c565b919091610120818403126102325761361b611013565b9261362582610236565b84526020820135602085015260408201356001600160401b03811161023257816136509184016135ea565b604085015260608201356001600160401b03811161023257816136749184016135ea565b60608501526080820135608085015260a082013560a085015260c082013560c085015260e08201356001600160401b03811161023257816136b69184016135ea565b60e08501526101008201356001600160401b038111610232576136d992016135ea565b610100830152565b90816020910312610232575190565b80516001600160a01b031682526120bc916020820151602082015261010061377161374161372f60408601516101206040870152610120860190610d6e565b60608601518582036060870152610d6e565b6080850151608085015260a085015160a085015260c085015160c085015260e085015184820360e0860152610d6e565b92015190610100818403910152610d6e565b9392916137a09060409286526060602087015260608601906136f0565b930152565b9291906137a06020916040865260408601906136f0565b9290925f926137cb3682613605565b916137da610100830183612009565b918193835f93602082101580613a1b575b6139dc575b5050506001600160f81b031916600160f81b145b6139b5575b506001600160f81b03198616600160f81b036138a0575050604051639700320360e01b815293602092859283915f91839161384791600484016137a5565b039260581c6001600160a01b03165af19081156107dc576120bc925f9261386f575b50614fce565b61389291925060203d602011613899575b61388a8183610fe3565b8101906136e1565b905f613869565b503d613880565b909491939092916001600160f81b03198116600160f91b036139515760081b93600160f01b6138d46134b96134b288612071565b16613942575f6138f46138ee60209661391e99858a614ddf565b94614fce565b604051630ccab7a160e01b8152979096889586948593926001600160e01b03191660048501613783565b03926001600160a01b03165af19081156107dc576120bc925f9261386f5750614fce565b6314b9743f60e01b5f5260045ffd5b919350506001600160f81b03191661244d576139a690630b135d3f60e11b9361350563ffffffff60e01b946020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b16036139b0575f90565b600190565b916139c293955086614ba7565b9193916139d0368284612a9c565b6101008401525f613809565b9195509250829196506139ef9350611d78565b90916139fc368385612a9c565b610100850152613804613a12600192339061308a565b95905f806137f0565b507f0555ad2729e8da1777a4e5020806f8bf7601c3db6bfe402f410a34958363a95a613a4a612c908484611d6a565b146137eb565b5f516020615f755f395f51905f5254600a63ffffffff8260a81c16019063ffffffff8211613b015763ffffffff83811692168211613af257613a9a9060c81c63ffffffff16610638565b10156105f9575f516020615f755f395f51905f52805463ffffffff60c81b60c893841b1663ffffffff60c81b1990911617908190559081901c63ffffffff9081169160a81c168111613ae95750565b6102419061228a565b63e60fd64760e01b5f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b60207f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae88918060581c6001600160581b0360a81b5f516020615f755f395f51905f525416175f516020615f755f395f51905f5255604051906001600160581b0319168152a1565b929490939193613b8d6127be85611ea5565b5f516020615f755f395f51905f525460a81c63ffffffff169063ffffffff808316911614613d84575b506020810180516001600160a01b031615613d7b575b5f516020615f755f395f51905f525460a81c63ffffffff1663ffffffff613bfa610638855163ffffffff1690565b911614801590613d4f575b6105f957613c53613c6092613c1987611ea5565b815181546020938401516001600160c01b031990911663ffffffff9290921691909117921b640100000000600160c01b0316919091179055565b516001600160a01b031690565b915f196001600160a01b03841601613d3e575b5050506001600160f81b03198116600160f81b03613d1b5760581c6001600160a01b031690813b15610232576040516306d61fe760e41b8152925f9184918291613cc191906004840161272d565b038183855af19081156107dc575f516020615f355f395f51905f52926128bc92613d07575060408051600181526001600160a01b03909216602083015290918291820190565b806107d65f613d1593610fe3565b5f612e48565b91506001600160f81b03198216600160f91b0361244d576102419160081b61513c565b613d4792614117565b5f8080613c73565b50613d5c6127be86611ea5565b63ffffffff613d72610638855163ffffffff1690565b91161015613c05565b60018152613bcc565b613d969060010163ffffffff1661228a565b5f613bb6565b6040908151613dab8382610fe3565b600681526512d95c9b995b60d21b602082015291613dcb81519182610fe3565b6005815264302e332e3360d81b602082015290565b91613e07925f8080946040519687958694859363d68f602560e01b8552336004860161218c565b03926001600160a01b03165af19081156107dc575f91613e25575090565b6120bc91503d805f833e6107fa8183610fe3565b5f9283613e0795936040519687958694859363d68f602560e01b8552336004860161218c565b5f9060405192808385378338925af4913d82523d5f602084013e60203d830101604052565b5f9192806040519485378338925af4913d82523d5f602084013e60203d830101604052565b6001600160a01b0316803b1561023257604051630b9dfbed60e11b815260206004820152915f918391829084908290613ee6906024830190610d6e565b03925af180156107dc57613ef75750565b5f61024191610fe3565b8051156122e65760200190565b80518210156122e65760209160051b010190565b909593919492965f5b87811015613f7b57600190613f758a89613f618489613f5a828060051b8c013595613f5587610986565b613f0e565b51946122cf565b90613f6d868d8d6122cf565b949093613b7b565b01613f2b565b509650505050505050565b90156122e65790565b9293929091906001600160a01b03821615614108575b613fae9061203b565b93613fda613fcd613fbf8684613f86565b356001600160f81b03191690565b6001600160f81b03191690565b936001600160f81b031985166140e0576001600160a01b0384169161400191908190611d95565b823b156102325761402b925f92836040518096819582946306d61fe760e41b84526004840161272d565b03925af19485156107dc5761408f6140af93600193610241986140cc575b5060408051600381526001600160a01b03881660208201525f516020615f355f395f51905f529190a15b82546001600160a01b0319166001600160a01b03909116178255565b0180546001600160a01b0319166001600160a01b03909316929092178255565b805460ff60a01b191660589290921c60ff60a01b16919091179055565b806107d65f6140da93610fe3565b5f614049565b50909390506001600160f81b0319808416036132ea5760016140af9161408f61024196614073565b6001600160a01b039150613fa5565b6001600160a01b031691908215801561425d575b6142585760405163d60b347f60e01b8152306004820152602081602481875afa9081156107dc575f91614239575b50158015614210575b61419a575b505060408051600481526001600160a01b0390921660208301525f516020615f355f395f51905f529190819081016128bc565b90806141a592611d95565b9190813b15610232576040516306d61fe760e41b8152925f91849182916141d091906004840161272d565b038183855af19081156107dc575f516020615f355f395f51905f52926128bc926141fc575b5091614167565b806107d65f61420a93610fe3565b5f6141f5565b50811515801561416257506001600160f81b031980614232613fbf8585613f86565b1614614162565b614252915060203d602011610831576108238183610fe3565b5f614159565b505050565b506001831461412b565b926142759092919284615434565b806142bb57915f929183612f456142a5829560405192839160208301966306d61fe760e41b88526024840161272d565b51926001600160a01b03165af1506126c56122f8565b6001600160a01b0390921691823b15610232576126b6925f92836040518096819582946306d61fe760e41b84526004840161272d565b7f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a9160609161432382610cea83611edc565b600160ff198254161790556040519163ffffffff60e01b1682526001600160581b031916602082015260016040820152a1565b907f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a9260609261438983610cea83611edc565b9115159160ff1981541660ff84161790556040519263ffffffff60e01b1683526001600160581b03191660208301526040820152a1565b6143ca5f9161203b565b80546001600160a01b031981168255600190910180546001600160a01b0390921693916001600160f81b0319605882901b1615614413575b5080546001600160a81b0319169055565b6001600160a01b031692505f614402565b906001600160581b03195f516020615f755f395f51905f525460581b166001600160581b0319831614612ce3576144706001600160a01b0361446584611ea5565b5460201c1692611ea5565b8054640100000000600160c01b0319169055565b91907f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3905a905f80604051936144e4856144d66020820196638a91b0e360e01b88526020602484018181520190610d6e565b03601f198101875286610fe3565b604051936144f3602086610fe3565b828552602085019583908a905f368a375193f1913d908161453a575b815f9293523e604080516001600160a01b0390951685528115156020860152909390819081016128bc565b5f915061450f565b604080519091906145538382610fe3565b6001815291601f1901825f5b82811061456b57505050565b80606060208093850101520161455f565b9061458682611023565b6145936040519182610fe3565b82815280926145a4601f1991611023565b01905f5b8281106145b457505050565b8060606020809385010152016145a8565b9060406120bc925f81528160208201520190610d6e565b600881901b9291906001600160f81b03198116600160f81b0361466f57509061460491615560565b90916001600160f81b0319811661461f57506120bc91615678565b6001600160f81b031916600160f81b0361463c576120bc916155cc565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b9293926001600160f81b0319811661472757509061468c916154e2565b91614695614542565b956001600160f81b031981166146c257506146af9361552a565b6146b883613f01565b526126c582613f01565b6001600160f81b031916600160f81b0361463c576146df93615503565b6146e884613f01565b52610241577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76128bc61471a84613f01565b51604051918291826145c5565b909391906001600160f81b03199081160361463c576147516147579161474b614542565b956154ba565b91613e84565b61476385939293613f01565b526001600160f81b03198116600160f81b036147ae57501561478157565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76128bc61471a84613f01565b6001600160f81b03191661463c576102415760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b6044820152606490fd5b903590601e198136030182121561023257018035906001600160401b03821161023257602001918160051b3603831361023257565b80548210156122e6575f5260205f2001905f90565b9092809260209483528483013701015f815290565b8054905f815581614869575050565b5f5260205f20908101905b81811061487f575050565b5f8155600101614874565b9091906001600160a01b03168015801561490b575b6142585781156122e6575f516020615f555f395f51905f52926128bc926001600160f81b031982358116146148f2575b505060408051600481526001600160a01b03909216602083015290918291820190565b612b1481612e429261490394611d95565b505f806148cf565b506001811461489f565b816040519182372090565b5f809160405136810160405236838237604051601481016040523360601b90528260143601925af190604051903d82523d5f602084013e60203d830101604052565b9182358060f81c805f146149a6578060011461499957600214614983575f80fd5b6001600160d81b03191692600501916004190190565b5092601501916014190190565b505060015f9301915f190190565b60405160208101917f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c8383526040820152604081526149f3606082610fe3565b5190209015614a05576120bc906157ea565b6120bc906156d8565b9190614a1b913691612a9c565b604051916020820191805180604014614aa657604114614a485750505050505b638baa579f5f526004601cfd5b80606060409201515f1a60205201516060525b5f52516040526020600160805f825afa51905f6060526040523d614a80575050614a3b565b6001600160a01b03163003614a9a57630b135d3f60e11b90565b6001600160e01b031990565b506040015160ff81901c601b016020526001600160ff1b0316606052614a5b565b90926080926120bc9694835260018060a01b0316602083015260408201528160608201520191612147565b614b0b65ffffffffffff929594614b179487338561585f565b97929491959095615929565b5091164210908115614b95575b50614b8257602094614b35916149b4565b60405163392dffaf60e01b815295869485938493614b6493929133906001600160e01b03191660048701614ac7565b03916001600160a01b03165afa9081156107dc575f9161345a575090565b506001600160e01b031995945050505050565b65ffffffffffff91501642115f614b24565b9190939293601481019160141161023257803560601c92829190614bc9612cfc565b6001600160a01b03909516602086019081529490614c28614bec6127be83611ea5565b5f516020615f755f395f51905f525460a81c63ffffffff169063ffffffff808316911603614d8d5760010163ffffffff165b63ffffffff168352565b815163ffffffff1695516001600160a01b031697614c468580612009565b614c4f91614915565b986034850199614c5f8b88612009565b614c6891614915565b906054870199614c788b8a612009565b614c8191614915565b604080517fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c505602082019081526001600160581b03198a169282019290925263ffffffff9390931660608401526001600160a01b0395909516608083015260a082019290925260c081019290925260e0808301919091528152614d0561010082610fe3565b519020905f1461052a6102ab98614d6660949861295097614d476128d49761053097614d7f57614d34906157ea565b614d4160748d0185612009565b91615bee565b9e614d5d614d558480612009565b929094612009565b9390928a613b7b565b614d79614d73828b612009565b90615d68565b88612009565b614d88906156d8565b614d34565b614c1e565b356001600160c01b0319811692919060088210614dad575050565b6001600160c01b031960089290920360031b82901b16169150565b6040906120bc9392815281602082015201906136f0565b93929190935f926001614df183612071565b015f5b8154811015614f7257614e0d612f15612f088385614830565b939095614e2f614e29614e23613fbf8585613f86565b60f81c90565b60ff1690565b808403614f445750908181614e68614e5c614e56614e5084614e8698611db1565b90614d92565b60c01c90565b6001600160401b031690565b600901918c610100614e7e612b14868686611dc2565b910152611e57565b939093955b600160f01b1615614ea3575b50600101939193614df4565b604051633894f6e760e11b81529196906020908390815f81614ed38f6001600160e01b03198d1660048401614dc8565b03926001600160a01b03165af19182156107dc575f92614f24575b506001600160a01b038216614f1057600191614f0991614fce565b9590614e97565b631f24c1fb60e11b5f52600487905260245ffd5b614f3d91925060203d81116138995761388a8183610fe3565b905f614eee565b9196909491831115614f5f57630760bdcf60e11b5f5260045ffd5b614f67612214565b6101008b0152614e8b565b505091929460ff80614f8a614e23613fbf8789613f86565b1603614fbf57610100614fa7612b1485614faf966120bc98611d95565b910152612071565b5460101c6001600160a01b031690565b63b32eeb6960e01b5f5260045ffd5b908082186001600160a01b031615606083811b838501821b9081149184901b141717600114614ffe575050600190565b65ffffffffffff60a01b8216916001600160d01b0319808216908316841561507e575b65ffffffffffff60a01b8416801561506e575b85811090861802808618951461505d575b81811190821802189160018060a01b03911716171790565b65ffffffffffff60a01b9450615045565b5065ffffffffffff60a01b615034565b65ffffffffffff60a01b9450615021565b356001600160501b03198116929190601682106150aa575050565b6001600160501b031960169290920360031b82901b16169150565b805468010000000000000000811015610f8c576150e791600182018155614830565b819291549060031b9160501c821b9160018060b01b03901b1916179055565b356001600160f01b0319811692919060028210615121575050565b6001600160f01b031960029290920360031b82901b16169150565b919061514890806147fb565b9260fe8411801561542c575b61541d57600161516382612071565b015461540a575b5f1984015f5b8181106152cc57509061522f61522883876151c86152196152006134b96151fa6151f487612ff99e9f8e6151ef61524b9f8f9061070561282d6128276151ba6151c09489896122cf565b90611ded565b9a8b91612071565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b6122cf565b90611e1b565b90615106565b61520988612071565b9060f01c61ffff19825416179055565b6001600160a01b0316966122cf565b8091611dfe565b6040519586939092906001600160e01b03191660208501614845565b803b15610232575f61527192604051809481926306d61fe760e41b8352600483016121b0565b038183855af19081156107dc575f516020615f355f395f51905f52926128bc926152b8575b5060408051600681526001600160a01b03909216602083015290918291820190565b806107d65f6152c693610fe3565b5f615296565b6153679061531260016152de86612071565b0161530c6152ff6152f96152f3868d8c6122cf565b90611ddf565b9061508f565b6001600160501b03191690565b906150c5565b61532c61070561070561282d6128276151ba868d8c6122cf565b61533a615228838a896122cf565b60405194918591615359916001600160e01b03198a1660208501614845565b03601f198101855284610fe3565b803b15610232576040516306d61fe760e41b8152925f91849182908490829061539390600483016121b0565b03925af19182156107dc576001926153f6575b505f516020615f355f395f51905f526153ed6153cc61282d6128276151ba868d8c6122cf565b60408051600581526001600160a01b03909216602083015290918291820190565b0390a101615170565b806107d65f61540493610fe3565b5f6153a6565b6154186001612fa483612071565b61516a565b63b62d956d60e01b5f5260045ffd5b508315615154565b5f516020615f355f395f51905f52916040916001600160a01b038216156154b1575b6001600160a01b039081165f8181527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b8660205284902080546001600160a01b03191693909216929092179055815190600282526020820152a1565b60019150615456565b9160138211156154d557823560601c92601401916013190190565b63ba597e7e5f526004601cfd5b9060338111156154d557813560601c92601483013592603401916033190190565b905f928491604051958692833738935af1913d82523d5f602084013e60203d830101604052565b90925f92819594604051968792833738935af115615557573d82523d5f602084013e60203d830101604052565b503d5f823e3d90fd5b918235826020118160401c176154d557830160208101938135938461558457505050565b01601f190190835b5f190160208160051b8301013580830160608101908135809101918680602080860135809601011191111792171760401c176154d5578061558c57505050565b91906155d78161457c565b925f5b8281106155e657505050565b8061561060019260051b840135840160408101358101906020823592019060208101359035615503565b61561a8389613f0e565b5215615627575b016155da565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76156706156558389613f0e565b51604051918291858352604060208401526040830190610d6e565b0390a1615621565b91906156838161457c565b925f5b82811061569257505050565b806156bc60019260051b84013584016040810135810190602082359201906020810135903561552a565b6156c68288613f0e565b526156d18187613f0e565b5001615686565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f000000000000000000000000000000000000000000000000000000000000000046141615615763575b6719010000000000005f52601a52603a526042601820905f603a52565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f0000000000000000000000000000000000000000000000000000000000000000604082015246606082015230608082015220615746565b60a06157f4613d9c565b90602081519101209060208151910120604051917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8352602083015260408201525f6060820152306080820152206719010000000000005f52601a52603a526042601820905f603a52565b949184846158e092969593966040519061587882610fc7565b5f82525f602083015260408201995f8b526158da606084019a8b925f84525f60808701525f60a0870152606060c08701526158cb60e08701915f83526101008801955f87529063ffffffff60e01b169052565b6001600160a01b039091169052565b52615980565b60ff806158f3614e23613fbf8786613f86565b1603614fbf57614faf61590d8461591d9561592294611d95565b9490955163ffffffff60e01b1690565b612071565b9351929190565b8065ffffffffffff8260a01c16918215600114615947575b60d01c92565b65ffffffffffff9250615941565b90926080926120bc9594835260018060a01b0316602083015260408201528160608201520190610d6e565b91606083019060016159d561599c845163ffffffff60e01b1690565b6001600160e01b0319165f9081527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f8526020526040902090565b01805493905f5b8581106159ec5750505050505050565b6159fc612f15612f088385614830565b6001600160a01b031660a0890190815260808901949091615a25906001600160f01b0319168652565b615a3f615a38614e23613fbf8985613f86565b60ff168a52565b615a4d614e298a5160ff1690565b808403615bbc5750858181615a72614e5c614e56614e50615ac79b9c615a9a98611db1565b8c60c0615a8d612b1460208401948086526009018688611dc2565b9101525160090191611e57565b949094955b51600160f11b90615ab9906001600160f01b0319166134b9565b166001600160f01b03191690565b15615ad6575b506001016159dc565b51615ae9906001600160a01b0316610705565b6020615b0f615b02615b02895163ffffffff60e01b1690565b6001600160e01b03191690565b60e08a01516101008b015160c08c015160405163184dfdbb60e11b8152958694909385938493615b4e9390926001600160a01b03169060048601615955565b03915afa9081156107dc575f91615b9e575b506001600160a01b038116615b8a5790600191615b8260408a01918251614fce565b905290615acd565b631f24c1fb60e11b5f52600482905260245ffd5b615bb6915060203d81116138995761388a8183610fe3565b5f615b60565b909490831115615bd557630760bdcf60e11b5f5260045ffd5b615ac790615be4365f88612a9c565b60c08b0152615a9f565b5f516020615f755f395f51905f52545f9493929060581b6001600160f81b03198116600160f81b03615ca95791615c4e9391615c2f61070560209560581c90565b9160405195869485938493637aa8f17760e11b8552306004860161218c565b03915afa9081156107dc575f91615c8a575b505b6001600160e01b0319166374eca2c160e11b01615c7b57565b6362467c7760e11b5f5260045ffd5b615ca3915060203d60201161347c576134748183610fe3565b5f615c60565b90949192916001600160f81b03198216600160f91b03615d4a5750602091615cd79160081b9584308861585f565b60405163392dffaf60e01b81529297929586949385938493615d0a93909230906001600160e01b03191660048701614ac7565b03916001600160a01b03165afa9081156107dc575f91615d2b575b50615c62565b615d44915060203d60201161347c576134748183610fe3565b5f615d25565b94906001600160f81b03191661244d57615d6392614a0e565b615c62565b615d756105308383611d20565b91602c8110615f1857602c820190615d9661070561282d6128278487611d4b565b615dc0615db2613fcd613fbf615dac8780612009565b90613f86565b6001600160f81b0319161590565b80615e73575b61070561282d61282785615e1b6102419a87615dff61070561282d6128278f9d6129579f9e8f604c9f6129d09f615e21575b5050611e46565b615e098b80612009565b9390926001600160a01b031690613f8f565b88611e46565b612957615e65615e6c93606c860190615e60615e4f61070561282d612827615e498787612009565b90611d5c565b9586906001600160a01b0316615434565b612009565b8091611e29565b8f87615df8565b5060405163ecd0596160e01b81526002600482015290949291906020816024816001600160a01b038a165afa9384156107dc5761282d61282784615e1b610705948b615dff61070561282d6102419f8f9c6129579f9d8f604c9f936129d09f94612827955f91615ef9575b509f50505050505050505097509a5050959650505050615dc6565b615f12915060203d602011610831576108238183610fe3565b5f615ede565b90506004915003615f2557565b637a210a5d60e11b5f5260045ffdfed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Deployed Bytecode
0x6080604052600436101561001d575b366131ab5761001b61317a565b005b5f3560e01c8063112d3a7d1461021c578063150b7a02146102175780631626ba7e1461021257806319822f7c1461020d5780631f1b92e3146102085780633659cfe6146102035780633c3b752b146101fe57806352141cd9146101f957806357b3a5f4146101f45780636e6fa0c6146101ef578063721e67f4146101ea57806384b0196e146101e55780638dd7712f146101e057806390ef8862146101db5780639198bdf5146101d65780639517e29f146101d15780639cfd7cff146101cc578063a65d69d4146101c7578063a71763a8146101c2578063adb610a3146101bd578063b8afe17d146101b8578063b9b82941146101b3578063bc197c81146101ae578063c3e58978146101a9578063d03c7914146101a4578063d691c9641461019f578063e6f3d50a1461019a578063e9ae5c5314610195578063f1f7f0f914610190578063f23a6e611461018b578063f2dc691d146101865763fc9c5dec0361000e57611cc0565b611c9f565b611c45565b611c0f565b611adf565b61195f565b61187d565b611830565b61175d565b61164c565b6114f5565b61147f565b61144d565b61131d565b6112d9565b611281565b611151565b61103a565b610f2b565b610e30565b610d92565b610d0c565b610cb1565b610bfe565b610a5e565b6109c8565b61084b565b610695565b610390565b61032f565b6102d5565b6102af565b6001600160a01b0381160361023257565b5f80fd5b359061024182610221565b565b9181601f84011215610232578235916001600160401b038311610232576020838186019501011161023257565b6060600319820112610232576004359160243561028c81610221565b91604435906001600160401b038211610232576102ab91600401610243565b9091565b346102325760206102cb6102c236610270565b92919091611f13565b6040519015158152f35b34610232576080366003190112610232576102f1600435610221565b6102fc602435610221565b6064356001600160401b0381116102325761031b903690600401610243565b5050604051630a85bd0160e11b8152602090f35b34610232576040366003190112610232576004356024356001600160401b0381116102325760209161036861036e923690600401610243565b91613377565b6040516001600160e01b03199091168152f35b90816101209103126102325790565b6060366003190112610232576004356001600160401b038111610232576103bb903690600401610381565b602435604435917f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b03163303610662576103ff60208201356135c3565b9092919084836001600160f81b0319861615610649575b8261042193946137bc565b9361044661043661043184611ea5565b611fdd565b946001600160f81b031916151590565b938480610608575b6105f957602001516001600160a01b0316801591819083806105f2575b6104f2576001926104866104a5925f525f60205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b149081156105ea575b501561055d5782610501575b50506104f257816104dc925b6104e0575b506040519081529081906020820190565b0390f35b3490349034903490335af1505f6104cb565b631a0a9b9f60e21b5f5260045ffd5b61055692506105529161053661053061052a61051f61054b95611edc565b936060810190612009565b90611d20565b90611e6f565b63ffffffff60e01b165f5260205260405f2090565b5460ff1690565b1590565b5f806104ba565b829192916105b7575b506104f25761052a81606061057c930190612009565b638dd7712f60e01b916001600160e01b03199161059891611e6f565b16036105a857816104dc926104c6565b63dbbb044b60e01b5f5260045ffd5b6105e4915061054b6105cb61055292611edc565b6105366105306105de6060880188612009565b90611d0f565b5f610566565b90505f6104ae565b508661046b565b633ab3447f60e11b5f5260045ffd5b50805163ffffffff1663ffffffff6106416106385f516020615f755f395f51905f525463ffffffff9060c81c1690565b63ffffffff1690565b91161061044e565b5f516020615f755f395f51905f525460581b9250610416565b6348f5c3ed60e01b5f5260045ffd5b6004359063ffffffff8216820361023257565b359063ffffffff8216820361023257565b6020366003190112610232576106a9610671565b337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580610841575b15610838576107116107056106ff5f516020615f755f395f51905f525460581b90565b60581c90565b6001600160a01b031690565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91610809575b50156106625760405163d68f602560e01b8152916001600160a01b0391909116905f838061076e36343360048501612167565b038183865af19283156107dc575f936107e1575b5061078c90613a50565b803b1561023257604051630b9dfbed60e11b8152915f9183918290849082906107b890600483016121b0565b03925af180156107dc576107c857005b806107d65f61001b93610fe3565b80610d64565b6120bf565b61078c919350610802903d805f833e6107fa8183610fe3565b8101906120e5565b9290610782565b61082b915060203d602011610831575b6108238183610fe3565b8101906120a7565b5f61073b565b503d610819565b61001b90613a50565b50303314156106dc565b60203660031901126102325760043561086381610221565b337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b031614158061097c575b15610973576108b96107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91610954575b50156106625760405163d68f602560e01b8152916001600160a01b0391909116905f838061091636343360048501612167565b038183865af19283156107dc575f93610934575b5061078c906121c1565b61078c91935061094d903d805f833e6107fa8183610fe3565b929061092a565b61096d915060203d602011610831576108238183610fe3565b5f6108e3565b61001b906121c1565b5030331415610896565b6001600160581b031981160361023257565b9181601f84011215610232578235916001600160401b038311610232576020808501948460051b01011161023257565b346102325760a0366003190112610232576004356109e581610986565b6024356109f181610221565b6044356001600160401b03811161023257610a10903690600401610243565b6064939193356001600160401b03811161023257610a32903690600401610243565b91608435956001600160401b03871161023257610a5661001b973690600401610998565b969095612327565b608036600319011261023257600435610a7681610986565b602435610a8281610221565b6044356001600160401b03811161023257610aa1903690600401610243565b6064356001600160401b03811161023257610ac0903690600401610243565b91337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580610be2575b15610bd457610b176107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91610bb5575b50156106625760405163d68f602560e01b8152956001600160a01b039190911694905f8780610b7536343360048501612167565b0381838a5af19687156107dc575f97610b95575b5061078c9596976124aa565b61078c969750610bae903d805f833e6107fa8183610fe3565b9695610b89565b610bce915060203d602011610831576108238183610fe3565b5f610b41565b919361001b959391936124aa565b5030331415610af4565b6001600160e01b031981160361023257565b34610232576020366003190112610232576104dc610c3f600435610c2181610bec565b5f60408051610c2f81610f71565b828152826020820152015261203b565b600160405191610c4e83610f71565b805460a083901b839003168084529101546001600160a01b0380821660208086019182526001600160f81b031960589490941b84166040968701908152865195841686529151909216918401919091525116918101919091529081906060820190565b3461023257604036600319011261023257602060ff610d00600435610cd581610986565b610cea60243591610ce583610bec565b611edc565b9063ffffffff60e01b165f5260205260405f2090565b54166040519015158152f35b34610232576020366003190112610232576020610d41600435610d2e81610221565b5f604051610d3b81610f91565b5261332a565b60405190610d4e82610f91565b546001600160a01b031690819052604051908152f35b5f91031261023257565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610232575f36600319011261023257610dd1610ddf610db0613d9c565b604092919251938493600f60f81b855260e0602086015260e0850190610d6e565b908382036040850152610d6e565b4660608301523060808301525f60a083015281810360c083015260206060519182815201906080905f5b818110610e17575050500390f35b8251845285945060209384019390920191600101610e09565b6040366003190112610232576004356001600160401b03811161023257610e5b903690600401610381565b6024357f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b03163303610662575f908152602081905260409020546001600160a01b03169060609060018314159081610efb575b610ed0610ec9826060610ed7940190612009565b8091611d2e565b9030613e84565b5015610eec57610ee357005b61001b91613ea9565b63f21e646b60e01b5f5260045ffd5b9150610ed7610ed0610ec9610f21610f19610ec96060880188612009565b903489613e39565b9492505050610eb5565b34610232575f36600319011261023257602063ffffffff5f516020615f755f395f51905f525460c81c16604051908152f35b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b03821117610f8c57604052565b610f5d565b602081019081106001600160401b03821117610f8c57604052565b604081019081106001600160401b03821117610f8c57604052565b61012081019081106001600160401b03821117610f8c57604052565b90601f801991011681019081106001600160401b03821117610f8c57604052565b60405190610241604083610fe3565b6040519061024161012083610fe3565b6001600160401b038111610f8c5760051b60200190565b6080366003190112610232576004356001600160401b03811161023257611065903690600401610998565b602435916001600160401b038311610232573660238401121561023257826004013561109081611023565b9361109e6040519586610fe3565b8185526024602086019260061b8201019036821161023257602401915b818310611110575050506044356001600160401b038111610232576110e4903690600401610998565b90606435946001600160401b0386116102325761110861001b963690600401610998565b9590946125af565b604083360312610232576020604091825161112a81610fac565b61113386610684565b81528286013561114281610221565b838201528152019201916110bb565b61115a36610270565b337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580611277575b1561126d576111b06107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f9161124e575b50156106625760405163d68f602560e01b8152936001600160a01b039190911692905f858061120e36343360048501612167565b038183885af19485156107dc575f9561122e575b5061078c93949561277e565b61078c949550611247903d805f833e6107fa8183610fe3565b9493611222565b611267915060203d602011610831576108238183610fe3565b5f6111da565b9161001b9361277e565b503033141561118d565b34610232575f366003190112610232576104dc6040516112a2604082610fe3565b60168152756b65726e656c2e616476616e6365642e76302e332e3360501b6020820152604051918291602083526020830190610d6e565b34610232575f366003190112610232576040517f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b03168152602090f35b61132636610270565b337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580611443575b156114395761137c6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f9161141a575b50156106625760405163d68f602560e01b8152936001600160a01b039190911692905f85806113da36343360048501612167565b038183885af19485156107dc575f956113fa575b5061078c939495612ad2565b61078c949550611413903d805f833e6107fa8183610fe3565b94936113ee565b611433915060203d602011610831576108238183610fe3565b5f6113a6565b9161001b93612ad2565b5030331415611359565b34610232575f36600319011261023257602063ffffffff5f516020615f755f395f51905f525460a81c16604051908152f35b346102325760203660031901126102325760406114af6004356114a181610986565b6114a9612cfc565b50611ea5565b8151906114bb82610fac565b5463ffffffff81168083526001600160a01b03602092831c81169383019384528451918252925190921690820152f35b8015150361023257565b60603660031901126102325760043561150d81610986565b60243561151981610bec565b604435611525816114eb565b337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580611642575b156116385761157b6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91611619575b50156106625760405163d68f602560e01b8152926001600160a01b039190911691905f84806115d936343360048501612167565b038183875af19384156107dc575f946115f9575b5061078c929394614356565b61078c939450611612903d805f833e6107fa8183610fe3565b93926115ed565b611632915060203d602011610831576108238183610fe3565b5f6115a5565b9061001b92614356565b5030331415611558565b346102325760a036600319011261023257611668600435610221565b611673602435610221565b6044356001600160401b03811161023257611692903690600401610998565b50506064356001600160401b038111610232576116b3903690600401610998565b50506084356001600160401b038111610232576116d4903690600401610243565b505060405163bc197c8160e01b8152602090f35b602080825282516001600160f01b03191681830152808301516001600160a01b03166040808401919091529092015160608083015280516080830181905260a09092019201905f5b81811061173d5750505090565b82516001600160501b031916845260209384019390920191600101611730565b346102325760203660031901126102325761179c60043561177d81610bec565b60606040805161178c81610f71565b5f81525f60208201520152612071565b6001604051916117ab83610f71565b805461ffff60f01b8160f01b168452828060a01b039060101c16602084015201906040519182602082549182815201915f5260205f20905f5b81811061180d576104dc85876117fc81880382610fe3565b6040820152604051918291826116e8565b825460501b6001600160501b0319168452602090930192600192830192016117e4565b346102325760203660031901126102325760206102cb600435612d14565b9060406003198301126102325760043591602435906001600160401b038211610232576102ab91600401610243565b6118863661184e565b90916001600160a01b036118993361332a565b54169182156119505760609060018414159485611939575b6118bb92936145dc565b92611929575b50506040518091602082016020835281518091526040830190602060408260051b8601019301915f905b8282106118fa57505050500390f35b919360019193955060206119198192603f198a82030186528851610d6e565b96019201920185949391926118eb565b61193291613ea9565b5f806118c1565b6118bb9250611949363487613de0565b92506118b1565b63710c949760e01b5f5260045ffd5b60603660031901126102325760043561197781610986565b6024356001600160401b03811161023257611996903690600401610243565b6044356001600160401b038111610232576119b5903690600401610243565b90337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580611ad5575b15611ac957611a0c6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91611aaa575b50156106625760405163d68f602560e01b8152946001600160a01b039190911693905f8680611a6a36343360048501612167565b038183895af19586156107dc575f96611a8a575b5061078c949596612dec565b61078c959650611aa3903d805f833e6107fa8183610fe3565b9594611a7e565b611ac3915060203d602011610831576108238183610fe3565b5f611a36565b91909261001b94612dec565b50303314156119e9565b611ae83661184e565b337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580611c05575b15611bfb57611b3e6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f91611bdc575b50156106625760405163d68f602560e01b8152926001600160a01b039190911691905f8480611b9c36343360048501612167565b038183875af19384156107dc575f94611bbc575b5061078c92939461307f565b61078c939450611bd5903d805f833e6107fa8183610fe3565b9392611bb0565b611bf5915060203d602011610831576108238183610fe3565b5f611b68565b9061001b9261307f565b5030331415611b1b565b34610232575f3660031901126102325760205f516020615f755f395f51905f525460581b604051906001600160581b0319168152f35b346102325760a036600319011261023257611c61600435610221565b611c6c602435610221565b6084356001600160401b03811161023257611c8b903690600401610243565b505060405163f23a6e6160e01b8152602090f35b34610232576020366003190112610232576020600435600760405191108152f35b34610232576040366003190112610232576004356001600160401b03811161023257611d07611cf56020923690600401610381565b60243590611d0282610221565b61308a565b604051908152f35b906008116102325760040190600490565b906004116102325790600490565b909291928360041161023257831161023257600401916003190190565b906018116102325760040190601490565b906014116102325790601490565b906020116102325790602090565b90929192836020116102325783116102325760200191601f190190565b909291928360011161023257831161023257600101915f190190565b906009116102325760010190600890565b909291928360091161023257831161023257600901916008190190565b906016116102325790601690565b906016116102325760020190601490565b909291928360161161023257831161023257601601916015190190565b906002116102325790600290565b909291928360141161023257831161023257601401916013190190565b90602c116102325760180190601490565b90939293848311610232578411610232578101920390565b356001600160e01b0319811692919060048210611e8a575050565b6001600160e01b031960049290920360031b82901b16169150565b6001600160581b0319165f527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f85060205260405f2090565b6001600160581b0319165f527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f85160205260405f2090565b90929060018103611f6257506001600160a01b0392611f5c9250611f4c915060581b600160581b600160f81b0316600160f81b17611ea5565b5460201c6001600160a01b031690565b16151590565b60028103611f9657506001600160a01b0392611f5c92506107059150611f8990841661332a565b546001600160a01b031690565b600303611fd657611fb7611fb2610530600193611fc595611d20565b61203b565b01546001600160a01b031690565b6001600160a01b0390811691161490565b5050505f90565b90604051611fea81610fac565b915463ffffffff81168352602090811c6001600160a01b031690830152565b903590601e198136030182121561023257018035906001600160401b0382116102325760200191813603831361023257565b63ffffffff60e01b165f527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b60205260405f2090565b63ffffffff60e01b165f527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f85260205260405f2090565b9081602091031261023257516120bc816114eb565b90565b6040513d5f823e3d90fd5b6001600160401b038111610f8c57601f01601f191660200190565b602081830312610232578051906001600160401b038211610232570181601f8201121561023257805190612118826120ca565b926121266040519485610fe3565b8284526020838301011161023257815f9260208093018386015e8301015290565b908060209392818452848401375f828201840152601f01601f1916010190565b6120bc939260609260018060a01b03168252602082015281604082015201905f612147565b6120bc949260609260018060a01b0316825260208201528160408201520191612147565b9060206120bc928181520190610d6e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8190556001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2565b60405190612223602083610fe3565b5f8252565b90813b5f612235826120ca565b936122436040519586610fe3565b82855260208501903c565b80516020909101516001600160e81b0319811692919060038210612270575050565b6001600160e81b0319600392830390921b82901b16169150565b5f516020615f755f395f51905f52805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b634e487b7160e01b5f52603260045260245ffd5b908210156122e6576102ab9160051b810190612009565b6122bb565b908092918237015f815290565b3d15612322573d90612309826120ca565b916123176040519384610fe3565b82523d5f602084013e565b606090565b94939291909695966001600160581b03196123606123535f516020615f755f395f51905f525460581b90565b6001600160581b03191690565b1615801590612482575b612474576001600160581b03198616156104f2576001600160f81b03198616600160f81b14158061245c575b61244d57856123a76123f497613b15565b6123c86123b2611004565b60018152925b6001600160a01b03166020840152565b5f516020615f755f395f51905f52805463ffffffff60a81b1916600160a81b179055613b7b565b613b7b565b5f5b81811061240257505050565b5f8061240f8385876122cf565b9061241f604051809381936122eb565b039082305af161242d6122f8565b501561243b576001016123f6565b636534eae560e11b5f5260045260245ffd5b6361c4e91b60e11b5f5260045ffd5b506001600160f81b03198616600160f91b1415612396565b62dc149f60e41b5f5260045ffd5b5061ef0160f01b6001600160e81b03196124a361249e30612228565b61224e565b161461236a565b94939291906001600160581b03198616156104f2576001600160f81b03198616600160f81b141580612555575b61244d576124e486613b15565b6001600160a01b036124f8611f4c88611ea5565b1615612507575b505050505050565b61254a956123ef61252d5f516020615f755f395f51905f525463ffffffff9060a81c1690565b926123b860405194612540604087610fe3565b63ffffffff168552565b5f80808080806124ff565b506001600160f81b03198616600160f91b14156124d7565b9060405161257a81610f71565b82546001600160a01b03908116825260019390930154928316602082015260589290921b6001600160f81b0319166040830152565b95909491939092337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b0316141580612723575b156127155761260c6107056106ff5f516020615f755f395f51905f525460581b90565b60405163ecd0596160e01b8152600480820152602081602481855afa9081156107dc575f916126f6575b50156106625760405163d68f602560e01b8152966001600160a01b039190911695905f888061266a36343360048501612167565b0381838b5af19788156107dc575f986126d6575b5061268a969798613f22565b803b1561023257604051630b9dfbed60e11b8152915f9183918290849082906126b690600483016121b0565b03925af180156107dc576126c8575b50565b806107d65f61024193610fe3565b61268a9798506126ef903d805f833e6107fa8183610fe3565b979661267e565b61270f915060203d602011610831576108238183610fe3565b5f612636565b919390929461024196613f22565b50303314156125e9565b9160206120bc938181520191612147565b356bffffffffffffffffffffffff1981169291906014821061275e575050565b6bffffffffffffffffffffffff1960149290920360031b82901b16169150565b9091600182036128fa575f516020615f355f395f51905f5293906054600160f81b600160581b600160f81b03605887901b1617916127c86127be84611ea5565b5463ffffffff1690565b5f516020615f755f395f51905f525460a81c63ffffffff169063ffffffff8083169116146128e2575b5061285a61283361070561282d6128276128205f516020615f755f395f51905f525463ffffffff9060a81c1690565b9886611d5c565b9061273e565b60601c90565b61284a61283e611004565b63ffffffff9097168752565b6001600160a01b03166020860152565b612885601482019461286c8680612009565b61287c6034869493940189612009565b93909288613b7b565b019160046128938483612009565b9050146128c1575b5050505b604080519182526001600160a01b03909216602082015290819081015b0390a1565b61053061052a6128da946128d493612009565b906142f1565b5f808061289b565b6128f49060010163ffffffff1661228a565b5f6127f1565b6002820361296257806129575f516020615f355f395f51905f5295603461293161070561282d612827601461295d99019588611d5c565b93612950856129408580612009565b906001600160a01b038c16614267565b0190612009565b91614117565b61289f565b600382036129d857806129575f516020615f355f395f51905f529560386129d061070561282d612827601861295d9901956129ca8c8a6129b861070561282d612827876129b26105308288611d20565b95611d4b565b6129c28b80612009565b939092613f8f565b88611d4b565b930190612009565b600482148015612a76575b8015612a6c575b15612a5d576001600160a01b03831693843b1561023257612a24945f92836040518098819582946306d61fe760e41b84526004840161272d565b03925af19283156107dc575f516020615f355f395f51905f5293612a49575b5061289f565b806107d65f612a5793610fe3565b5f612a43565b631092ef5760e11b5f5260045ffd5b50600682146129ea565b50600582146129e3565b359060208110612a8e575090565b5f199060200360031b1b1690565b929192612aa8826120ca565b91612ab66040519384610fe3565b829481845281830111610232578281602093845f960137010152565b909160018203612b43575f516020615f555f395f51905f5293612b2191612b1b91612b12600160f81b600160581b600160f81b03605889901b1617614424565b505b3691612a9c565b83614484565b50604080519182526001600160a01b03909216602082015290819081016128bc565b60028203612bb3576001600160a01b038381165f9081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902080546001600160a01b031981169091555f516020615f555f395f51905f5295612b2193612b1b939092165b50612b14565b919060038103612bd8575050610530612bd492612bcf92611d20565b6143c0565b5050565b909160048203612c6157612b1b612b21915f516020615f555f395f51905f5295612c105f516020615f755f395f51905f525460581b90565b612c1c611f4c82611ea5565b6001600160a01b03888116911614612c345750612b14565b612c40612c5b91611ea5565b8054640100000000600160c01b031916640100000000179055565b5f612bad565b600582148015612cf2575b15612a5d575f516020615f755f395f51905f525460581b612c96612c908684611d6a565b90612a80565b906001600160f81b03198116600160f91b14612cca575b5050612b1b612b21915f516020615f555f395f51905f5295612b14565b60081b6001600160e01b03191614612ce3575f80612cad565b6313002bdd60e31b5f5260045ffd5b5060068214612c6c565b60405190612d0982610fac565b5f6020838281520152565b612d28818060081b918160301b9160501b90565b929091906001600160f81b03198116600160f81b14159081612dd8575b81612dc3575b81612daa575b50611fd65760ff60f81b16600160f81b8114159081612da0575b50612d9a576001600160e01b031916612d95576001600160501b031916612d9157600190565b5f90565b505f90565b50505f90565b905015155f612d6b565b6001600160f81b031916607f60f91b141590505f612d51565b6001600160f81b031980821614159150612d4b565b6001600160f81b0319811615159150612d45565b9094939291612dfa82614424565b916001600160f81b03198116600160f81b03612e72575f516020615f555f395f51905f5291612e48612e426102419899612e6a9460018060a01b039060581c16933691612a9c565b82614484565b5060408051600181526001600160a01b03909216602083015290918291820190565b0390a161488a565b9294919290506001600160f81b03198116600160f91b0361244d5760081b92612e9a84612071565b94612ea587806147fb565b94905060018701946001865401036130705794956001600160e01b0319871695905f5b8654811015612f7e57805f516020615f555f395f51905f52612f758c612f53612f45612e428e612f338f99612f2d612f1d612f15612f088460019f614830565b90549060031b1c60501b90565b908160501c90565b90508c8060a01b031697806147fb565b906122cf565b60409491945194859360208501614845565b03601f198101835282610fe3565b5060408051600581526001600160a01b03909216602083015290918291820190565b0390a101612ec8565b509194509296612ff961300c9161300761306b9598612faa6001612fa46102419d612071565b0161485a565b8554612fe790612fc59060101c6001600160a01b0316610705565b93612fdc612fd382806147fb565b919092806147fb565b5f19019290506122cf565b60409591955195869360208501614845565b03601f198101845283610fe3565b614484565b5080545f516020615f555f395f51905f5290613058906130379060101c6001600160a01b0316610705565b60408051600681526001600160a01b03909216602083015290918291820190565b0390a180546001600160b01b0319169055565b61488a565b63013dcc8d60e31b5f5260045ffd5b906126c592916145dc565b612f4590613174906130a56001600160a01b03823516610705565b906131466020820135612f456130c76130c16040860186612009565b90614915565b936130d86130c16060830183612009565b90608081013560a0820135906130fa6130c160c08501359460e0810190612009565b93604051988997602089019b8c94919260e0969399989794919961010087019a60018060a01b03168752602087015260408601526060850152608084015260a083015260c08201520152565b51902060408051602081019283526001600160a01b03909516908501525f6060850152929182906080820190565b51902090565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460408051338152346020820152a1565b6131c76131c25f356001600160e01b03191661203b565b61256d565b80516001600160a01b03906131dd908216610705565b161561331b5780516060906001600160a01b0316806002600160a01b031981016132f95750507f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b03163303610662575b60408201516001600160f81b031916806132b957506020820151613260906001600160a01b0316614920565b92905b156132b157516001600160a01b0316906001821415828161329d575b5061328d575b825160208401f35b61329691613ea9565b5f80613285565b6001600160a01b039150811614155f61327f565b825160208401fd5b6001600160f81b0319908116036132ea5760208201516132e3906001600160a01b03163690613e5f565b9290613263565b632d6a6bb760e01b5f5260045ffd5b600103613307575b50613234565b613315915036903490613de0565b5f613301565b631cd4b64760e21b5f5260045ffd5b6001600160a01b03165f9081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b9081602091031261023257516120bc81610bec565b9161338191614962565b919080836001600160f81b03198416156135a3575b6020811015918261356c575b82613556575b50506133b661043184611ea5565b60208101516001600160a01b03906133cf908216610705565b161580613543575b6104f2576001600160f81b031984161515908161350a575b506105f9576001600160f81b03198316600160f81b03613483579061341b6020949392613439966149b4565b604051637aa8f17760e11b815295869485938493336004860161218c565b039160581c6001600160a01b03165afa9081156107dc575f9161345a575090565b6120bc915060203d60201161347c575b6134748183610fe3565b810190613362565b503d61346a565b92916001600160f81b03198116600160f91b036134e35760081b93600160f11b6134c66134b96134b288612071565b5460f01b90565b6001600160f01b03191690565b166134d4576120bc94614af2565b635b71057960e01b5f5260045ffd5b929391929091906001600160f81b03191661244d576120bc93613505916149b4565b614a0e565b5163ffffffff16905063ffffffff61353a6106385f516020615f755f395f51905f525463ffffffff9060c81c1690565b9116105f6133ef565b506001600160f81b0319841615156133d7565b819295506135649350611d78565b925f806133a8565b91507f0555ad2729e8da1777a4e5020806f8bf7601c3db6bfe402f410a34958363a95a61359c612c908385611d6a565b14916133a2565b92506135bd5f516020615f755f395f51905f525460581b90565b92613396565b90818060081b9160ff839260f01c166002146135db57565b6001600160d81b031983169150565b9080601f83011215610232578160206120bc93359101612a9c565b919091610120818403126102325761361b611013565b9261362582610236565b84526020820135602085015260408201356001600160401b03811161023257816136509184016135ea565b604085015260608201356001600160401b03811161023257816136749184016135ea565b60608501526080820135608085015260a082013560a085015260c082013560c085015260e08201356001600160401b03811161023257816136b69184016135ea565b60e08501526101008201356001600160401b038111610232576136d992016135ea565b610100830152565b90816020910312610232575190565b80516001600160a01b031682526120bc916020820151602082015261010061377161374161372f60408601516101206040870152610120860190610d6e565b60608601518582036060870152610d6e565b6080850151608085015260a085015160a085015260c085015160c085015260e085015184820360e0860152610d6e565b92015190610100818403910152610d6e565b9392916137a09060409286526060602087015260608601906136f0565b930152565b9291906137a06020916040865260408601906136f0565b9290925f926137cb3682613605565b916137da610100830183612009565b918193835f93602082101580613a1b575b6139dc575b5050506001600160f81b031916600160f81b145b6139b5575b506001600160f81b03198616600160f81b036138a0575050604051639700320360e01b815293602092859283915f91839161384791600484016137a5565b039260581c6001600160a01b03165af19081156107dc576120bc925f9261386f575b50614fce565b61389291925060203d602011613899575b61388a8183610fe3565b8101906136e1565b905f613869565b503d613880565b909491939092916001600160f81b03198116600160f91b036139515760081b93600160f01b6138d46134b96134b288612071565b16613942575f6138f46138ee60209661391e99858a614ddf565b94614fce565b604051630ccab7a160e01b8152979096889586948593926001600160e01b03191660048501613783565b03926001600160a01b03165af19081156107dc576120bc925f9261386f5750614fce565b6314b9743f60e01b5f5260045ffd5b919350506001600160f81b03191661244d576139a690630b135d3f60e11b9361350563ffffffff60e01b946020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b16036139b0575f90565b600190565b916139c293955086614ba7565b9193916139d0368284612a9c565b6101008401525f613809565b9195509250829196506139ef9350611d78565b90916139fc368385612a9c565b610100850152613804613a12600192339061308a565b95905f806137f0565b507f0555ad2729e8da1777a4e5020806f8bf7601c3db6bfe402f410a34958363a95a613a4a612c908484611d6a565b146137eb565b5f516020615f755f395f51905f5254600a63ffffffff8260a81c16019063ffffffff8211613b015763ffffffff83811692168211613af257613a9a9060c81c63ffffffff16610638565b10156105f9575f516020615f755f395f51905f52805463ffffffff60c81b60c893841b1663ffffffff60c81b1990911617908190559081901c63ffffffff9081169160a81c168111613ae95750565b6102419061228a565b63e60fd64760e01b5f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b60207f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae88918060581c6001600160581b0360a81b5f516020615f755f395f51905f525416175f516020615f755f395f51905f5255604051906001600160581b0319168152a1565b929490939193613b8d6127be85611ea5565b5f516020615f755f395f51905f525460a81c63ffffffff169063ffffffff808316911614613d84575b506020810180516001600160a01b031615613d7b575b5f516020615f755f395f51905f525460a81c63ffffffff1663ffffffff613bfa610638855163ffffffff1690565b911614801590613d4f575b6105f957613c53613c6092613c1987611ea5565b815181546020938401516001600160c01b031990911663ffffffff9290921691909117921b640100000000600160c01b0316919091179055565b516001600160a01b031690565b915f196001600160a01b03841601613d3e575b5050506001600160f81b03198116600160f81b03613d1b5760581c6001600160a01b031690813b15610232576040516306d61fe760e41b8152925f9184918291613cc191906004840161272d565b038183855af19081156107dc575f516020615f355f395f51905f52926128bc92613d07575060408051600181526001600160a01b03909216602083015290918291820190565b806107d65f613d1593610fe3565b5f612e48565b91506001600160f81b03198216600160f91b0361244d576102419160081b61513c565b613d4792614117565b5f8080613c73565b50613d5c6127be86611ea5565b63ffffffff613d72610638855163ffffffff1690565b91161015613c05565b60018152613bcc565b613d969060010163ffffffff1661228a565b5f613bb6565b6040908151613dab8382610fe3565b600681526512d95c9b995b60d21b602082015291613dcb81519182610fe3565b6005815264302e332e3360d81b602082015290565b91613e07925f8080946040519687958694859363d68f602560e01b8552336004860161218c565b03926001600160a01b03165af19081156107dc575f91613e25575090565b6120bc91503d805f833e6107fa8183610fe3565b5f9283613e0795936040519687958694859363d68f602560e01b8552336004860161218c565b5f9060405192808385378338925af4913d82523d5f602084013e60203d830101604052565b5f9192806040519485378338925af4913d82523d5f602084013e60203d830101604052565b6001600160a01b0316803b1561023257604051630b9dfbed60e11b815260206004820152915f918391829084908290613ee6906024830190610d6e565b03925af180156107dc57613ef75750565b5f61024191610fe3565b8051156122e65760200190565b80518210156122e65760209160051b010190565b909593919492965f5b87811015613f7b57600190613f758a89613f618489613f5a828060051b8c013595613f5587610986565b613f0e565b51946122cf565b90613f6d868d8d6122cf565b949093613b7b565b01613f2b565b509650505050505050565b90156122e65790565b9293929091906001600160a01b03821615614108575b613fae9061203b565b93613fda613fcd613fbf8684613f86565b356001600160f81b03191690565b6001600160f81b03191690565b936001600160f81b031985166140e0576001600160a01b0384169161400191908190611d95565b823b156102325761402b925f92836040518096819582946306d61fe760e41b84526004840161272d565b03925af19485156107dc5761408f6140af93600193610241986140cc575b5060408051600381526001600160a01b03881660208201525f516020615f355f395f51905f529190a15b82546001600160a01b0319166001600160a01b03909116178255565b0180546001600160a01b0319166001600160a01b03909316929092178255565b805460ff60a01b191660589290921c60ff60a01b16919091179055565b806107d65f6140da93610fe3565b5f614049565b50909390506001600160f81b0319808416036132ea5760016140af9161408f61024196614073565b6001600160a01b039150613fa5565b6001600160a01b031691908215801561425d575b6142585760405163d60b347f60e01b8152306004820152602081602481875afa9081156107dc575f91614239575b50158015614210575b61419a575b505060408051600481526001600160a01b0390921660208301525f516020615f355f395f51905f529190819081016128bc565b90806141a592611d95565b9190813b15610232576040516306d61fe760e41b8152925f91849182916141d091906004840161272d565b038183855af19081156107dc575f516020615f355f395f51905f52926128bc926141fc575b5091614167565b806107d65f61420a93610fe3565b5f6141f5565b50811515801561416257506001600160f81b031980614232613fbf8585613f86565b1614614162565b614252915060203d602011610831576108238183610fe3565b5f614159565b505050565b506001831461412b565b926142759092919284615434565b806142bb57915f929183612f456142a5829560405192839160208301966306d61fe760e41b88526024840161272d565b51926001600160a01b03165af1506126c56122f8565b6001600160a01b0390921691823b15610232576126b6925f92836040518096819582946306d61fe760e41b84526004840161272d565b7f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a9160609161432382610cea83611edc565b600160ff198254161790556040519163ffffffff60e01b1682526001600160581b031916602082015260016040820152a1565b907f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a9260609261438983610cea83611edc565b9115159160ff1981541660ff84161790556040519263ffffffff60e01b1683526001600160581b03191660208301526040820152a1565b6143ca5f9161203b565b80546001600160a01b031981168255600190910180546001600160a01b0390921693916001600160f81b0319605882901b1615614413575b5080546001600160a81b0319169055565b6001600160a01b031692505f614402565b906001600160581b03195f516020615f755f395f51905f525460581b166001600160581b0319831614612ce3576144706001600160a01b0361446584611ea5565b5460201c1692611ea5565b8054640100000000600160c01b0319169055565b91907f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3905a905f80604051936144e4856144d66020820196638a91b0e360e01b88526020602484018181520190610d6e565b03601f198101875286610fe3565b604051936144f3602086610fe3565b828552602085019583908a905f368a375193f1913d908161453a575b815f9293523e604080516001600160a01b0390951685528115156020860152909390819081016128bc565b5f915061450f565b604080519091906145538382610fe3565b6001815291601f1901825f5b82811061456b57505050565b80606060208093850101520161455f565b9061458682611023565b6145936040519182610fe3565b82815280926145a4601f1991611023565b01905f5b8281106145b457505050565b8060606020809385010152016145a8565b9060406120bc925f81528160208201520190610d6e565b600881901b9291906001600160f81b03198116600160f81b0361466f57509061460491615560565b90916001600160f81b0319811661461f57506120bc91615678565b6001600160f81b031916600160f81b0361463c576120bc916155cc565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b9293926001600160f81b0319811661472757509061468c916154e2565b91614695614542565b956001600160f81b031981166146c257506146af9361552a565b6146b883613f01565b526126c582613f01565b6001600160f81b031916600160f81b0361463c576146df93615503565b6146e884613f01565b52610241577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76128bc61471a84613f01565b51604051918291826145c5565b909391906001600160f81b03199081160361463c576147516147579161474b614542565b956154ba565b91613e84565b61476385939293613f01565b526001600160f81b03198116600160f81b036147ae57501561478157565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76128bc61471a84613f01565b6001600160f81b03191661463c576102415760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b6044820152606490fd5b903590601e198136030182121561023257018035906001600160401b03821161023257602001918160051b3603831361023257565b80548210156122e6575f5260205f2001905f90565b9092809260209483528483013701015f815290565b8054905f815581614869575050565b5f5260205f20908101905b81811061487f575050565b5f8155600101614874565b9091906001600160a01b03168015801561490b575b6142585781156122e6575f516020615f555f395f51905f52926128bc926001600160f81b031982358116146148f2575b505060408051600481526001600160a01b03909216602083015290918291820190565b612b1481612e429261490394611d95565b505f806148cf565b506001811461489f565b816040519182372090565b5f809160405136810160405236838237604051601481016040523360601b90528260143601925af190604051903d82523d5f602084013e60203d830101604052565b9182358060f81c805f146149a6578060011461499957600214614983575f80fd5b6001600160d81b03191692600501916004190190565b5092601501916014190190565b505060015f9301915f190190565b60405160208101917f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c8383526040820152604081526149f3606082610fe3565b5190209015614a05576120bc906157ea565b6120bc906156d8565b9190614a1b913691612a9c565b604051916020820191805180604014614aa657604114614a485750505050505b638baa579f5f526004601cfd5b80606060409201515f1a60205201516060525b5f52516040526020600160805f825afa51905f6060526040523d614a80575050614a3b565b6001600160a01b03163003614a9a57630b135d3f60e11b90565b6001600160e01b031990565b506040015160ff81901c601b016020526001600160ff1b0316606052614a5b565b90926080926120bc9694835260018060a01b0316602083015260408201528160608201520191612147565b614b0b65ffffffffffff929594614b179487338561585f565b97929491959095615929565b5091164210908115614b95575b50614b8257602094614b35916149b4565b60405163392dffaf60e01b815295869485938493614b6493929133906001600160e01b03191660048701614ac7565b03916001600160a01b03165afa9081156107dc575f9161345a575090565b506001600160e01b031995945050505050565b65ffffffffffff91501642115f614b24565b9190939293601481019160141161023257803560601c92829190614bc9612cfc565b6001600160a01b03909516602086019081529490614c28614bec6127be83611ea5565b5f516020615f755f395f51905f525460a81c63ffffffff169063ffffffff808316911603614d8d5760010163ffffffff165b63ffffffff168352565b815163ffffffff1695516001600160a01b031697614c468580612009565b614c4f91614915565b986034850199614c5f8b88612009565b614c6891614915565b906054870199614c788b8a612009565b614c8191614915565b604080517fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c505602082019081526001600160581b03198a169282019290925263ffffffff9390931660608401526001600160a01b0395909516608083015260a082019290925260c081019290925260e0808301919091528152614d0561010082610fe3565b519020905f1461052a6102ab98614d6660949861295097614d476128d49761053097614d7f57614d34906157ea565b614d4160748d0185612009565b91615bee565b9e614d5d614d558480612009565b929094612009565b9390928a613b7b565b614d79614d73828b612009565b90615d68565b88612009565b614d88906156d8565b614d34565b614c1e565b356001600160c01b0319811692919060088210614dad575050565b6001600160c01b031960089290920360031b82901b16169150565b6040906120bc9392815281602082015201906136f0565b93929190935f926001614df183612071565b015f5b8154811015614f7257614e0d612f15612f088385614830565b939095614e2f614e29614e23613fbf8585613f86565b60f81c90565b60ff1690565b808403614f445750908181614e68614e5c614e56614e5084614e8698611db1565b90614d92565b60c01c90565b6001600160401b031690565b600901918c610100614e7e612b14868686611dc2565b910152611e57565b939093955b600160f01b1615614ea3575b50600101939193614df4565b604051633894f6e760e11b81529196906020908390815f81614ed38f6001600160e01b03198d1660048401614dc8565b03926001600160a01b03165af19182156107dc575f92614f24575b506001600160a01b038216614f1057600191614f0991614fce565b9590614e97565b631f24c1fb60e11b5f52600487905260245ffd5b614f3d91925060203d81116138995761388a8183610fe3565b905f614eee565b9196909491831115614f5f57630760bdcf60e11b5f5260045ffd5b614f67612214565b6101008b0152614e8b565b505091929460ff80614f8a614e23613fbf8789613f86565b1603614fbf57610100614fa7612b1485614faf966120bc98611d95565b910152612071565b5460101c6001600160a01b031690565b63b32eeb6960e01b5f5260045ffd5b908082186001600160a01b031615606083811b838501821b9081149184901b141717600114614ffe575050600190565b65ffffffffffff60a01b8216916001600160d01b0319808216908316841561507e575b65ffffffffffff60a01b8416801561506e575b85811090861802808618951461505d575b81811190821802189160018060a01b03911716171790565b65ffffffffffff60a01b9450615045565b5065ffffffffffff60a01b615034565b65ffffffffffff60a01b9450615021565b356001600160501b03198116929190601682106150aa575050565b6001600160501b031960169290920360031b82901b16169150565b805468010000000000000000811015610f8c576150e791600182018155614830565b819291549060031b9160501c821b9160018060b01b03901b1916179055565b356001600160f01b0319811692919060028210615121575050565b6001600160f01b031960029290920360031b82901b16169150565b919061514890806147fb565b9260fe8411801561542c575b61541d57600161516382612071565b015461540a575b5f1984015f5b8181106152cc57509061522f61522883876151c86152196152006134b96151fa6151f487612ff99e9f8e6151ef61524b9f8f9061070561282d6128276151ba6151c09489896122cf565b90611ded565b9a8b91612071565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b6122cf565b90611e1b565b90615106565b61520988612071565b9060f01c61ffff19825416179055565b6001600160a01b0316966122cf565b8091611dfe565b6040519586939092906001600160e01b03191660208501614845565b803b15610232575f61527192604051809481926306d61fe760e41b8352600483016121b0565b038183855af19081156107dc575f516020615f355f395f51905f52926128bc926152b8575b5060408051600681526001600160a01b03909216602083015290918291820190565b806107d65f6152c693610fe3565b5f615296565b6153679061531260016152de86612071565b0161530c6152ff6152f96152f3868d8c6122cf565b90611ddf565b9061508f565b6001600160501b03191690565b906150c5565b61532c61070561070561282d6128276151ba868d8c6122cf565b61533a615228838a896122cf565b60405194918591615359916001600160e01b03198a1660208501614845565b03601f198101855284610fe3565b803b15610232576040516306d61fe760e41b8152925f91849182908490829061539390600483016121b0565b03925af19182156107dc576001926153f6575b505f516020615f355f395f51905f526153ed6153cc61282d6128276151ba868d8c6122cf565b60408051600581526001600160a01b03909216602083015290918291820190565b0390a101615170565b806107d65f61540493610fe3565b5f6153a6565b6154186001612fa483612071565b61516a565b63b62d956d60e01b5f5260045ffd5b508315615154565b5f516020615f355f395f51905f52916040916001600160a01b038216156154b1575b6001600160a01b039081165f8181527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b8660205284902080546001600160a01b03191693909216929092179055815190600282526020820152a1565b60019150615456565b9160138211156154d557823560601c92601401916013190190565b63ba597e7e5f526004601cfd5b9060338111156154d557813560601c92601483013592603401916033190190565b905f928491604051958692833738935af1913d82523d5f602084013e60203d830101604052565b90925f92819594604051968792833738935af115615557573d82523d5f602084013e60203d830101604052565b503d5f823e3d90fd5b918235826020118160401c176154d557830160208101938135938461558457505050565b01601f190190835b5f190160208160051b8301013580830160608101908135809101918680602080860135809601011191111792171760401c176154d5578061558c57505050565b91906155d78161457c565b925f5b8281106155e657505050565b8061561060019260051b840135840160408101358101906020823592019060208101359035615503565b61561a8389613f0e565b5215615627575b016155da565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76156706156558389613f0e565b51604051918291858352604060208401526040830190610d6e565b0390a1615621565b91906156838161457c565b925f5b82811061569257505050565b806156bc60019260051b84013584016040810135810190602082359201906020810135903561552a565b6156c68288613f0e565b526156d18187613f0e565b5001615686565b7ffb352e4c2d092ed0833b10ac7a7334878d30253a005bb06dbfd98eadcc99e1817f000000000000000000000000d6cedde84be40893d153be9d467cd6ad37875b2830147f000000000000000000000000000000000000000000000000000000000000000a46141615615763575b6719010000000000005f52601a52603a526042601820905f603a52565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f32ba20807d2fff2dbb34e0bcfa82982565bef566d4c0c633dc57b700b81c342760208201527fe59f6ee1eb8c975b97f1f46d5710db9d8e551d6906f9446e8530ab7bac85a99a604082015246606082015230608082015220615746565b60a06157f4613d9c565b90602081519101209060208151910120604051917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8352602083015260408201525f6060820152306080820152206719010000000000005f52601a52603a526042601820905f603a52565b949184846158e092969593966040519061587882610fc7565b5f82525f602083015260408201995f8b526158da606084019a8b925f84525f60808701525f60a0870152606060c08701526158cb60e08701915f83526101008801955f87529063ffffffff60e01b169052565b6001600160a01b039091169052565b52615980565b60ff806158f3614e23613fbf8786613f86565b1603614fbf57614faf61590d8461591d9561592294611d95565b9490955163ffffffff60e01b1690565b612071565b9351929190565b8065ffffffffffff8260a01c16918215600114615947575b60d01c92565b65ffffffffffff9250615941565b90926080926120bc9594835260018060a01b0316602083015260408201528160608201520190610d6e565b91606083019060016159d561599c845163ffffffff60e01b1690565b6001600160e01b0319165f9081527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f8526020526040902090565b01805493905f5b8581106159ec5750505050505050565b6159fc612f15612f088385614830565b6001600160a01b031660a0890190815260808901949091615a25906001600160f01b0319168652565b615a3f615a38614e23613fbf8985613f86565b60ff168a52565b615a4d614e298a5160ff1690565b808403615bbc5750858181615a72614e5c614e56614e50615ac79b9c615a9a98611db1565b8c60c0615a8d612b1460208401948086526009018688611dc2565b9101525160090191611e57565b949094955b51600160f11b90615ab9906001600160f01b0319166134b9565b166001600160f01b03191690565b15615ad6575b506001016159dc565b51615ae9906001600160a01b0316610705565b6020615b0f615b02615b02895163ffffffff60e01b1690565b6001600160e01b03191690565b60e08a01516101008b015160c08c015160405163184dfdbb60e11b8152958694909385938493615b4e9390926001600160a01b03169060048601615955565b03915afa9081156107dc575f91615b9e575b506001600160a01b038116615b8a5790600191615b8260408a01918251614fce565b905290615acd565b631f24c1fb60e11b5f52600482905260245ffd5b615bb6915060203d81116138995761388a8183610fe3565b5f615b60565b909490831115615bd557630760bdcf60e11b5f5260045ffd5b615ac790615be4365f88612a9c565b60c08b0152615a9f565b5f516020615f755f395f51905f52545f9493929060581b6001600160f81b03198116600160f81b03615ca95791615c4e9391615c2f61070560209560581c90565b9160405195869485938493637aa8f17760e11b8552306004860161218c565b03915afa9081156107dc575f91615c8a575b505b6001600160e01b0319166374eca2c160e11b01615c7b57565b6362467c7760e11b5f5260045ffd5b615ca3915060203d60201161347c576134748183610fe3565b5f615c60565b90949192916001600160f81b03198216600160f91b03615d4a5750602091615cd79160081b9584308861585f565b60405163392dffaf60e01b81529297929586949385938493615d0a93909230906001600160e01b03191660048701614ac7565b03916001600160a01b03165afa9081156107dc575f91615d2b575b50615c62565b615d44915060203d60201161347c576134748183610fe3565b5f615d25565b94906001600160f81b03191661244d57615d6392614a0e565b615c62565b615d756105308383611d20565b91602c8110615f1857602c820190615d9661070561282d6128278487611d4b565b615dc0615db2613fcd613fbf615dac8780612009565b90613f86565b6001600160f81b0319161590565b80615e73575b61070561282d61282785615e1b6102419a87615dff61070561282d6128278f9d6129579f9e8f604c9f6129d09f615e21575b5050611e46565b615e098b80612009565b9390926001600160a01b031690613f8f565b88611e46565b612957615e65615e6c93606c860190615e60615e4f61070561282d612827615e498787612009565b90611d5c565b9586906001600160a01b0316615434565b612009565b8091611e29565b8f87615df8565b5060405163ecd0596160e01b81526002600482015290949291906020816024816001600160a01b038a165afa9384156107dc5761282d61282784615e1b610705948b615dff61070561282d6102419f8f9c6129579f9d8f604c9f936129d09f94612827955f91615ef9575b509f50505050505050505097509a5050959650505050615dc6565b615f12915060203d602011610831576108238183610fe3565b5f615ede565b90506004915003615f2557565b637a210a5d60e11b5f5260045ffdfed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f
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
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.